blob: e7bb223b45b2a4bf0780907a4c7e28ca123c5f0e [file] [log] [blame]
Thierry Fourniere726b142016-02-11 17:57:57 +01001/*
2 * Lua unsafe core engine
3 *
4 * Copyright 2015-2016 Thierry Fournier <tfournier@arpalert.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Bertrand Jacquinf4c12d42021-01-21 21:14:07 +000013#define _GNU_SOURCE
14
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +010015#include <ctype.h>
Thierry FOURNIERbabae282015-09-17 11:36:37 +020016#include <setjmp.h>
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +010017
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010018#include <lauxlib.h>
19#include <lua.h>
20#include <lualib.h>
21
Thierry FOURNIER463119c2015-03-10 00:35:36 +010022#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503
23#error "Requires Lua 5.3 or later."
Cyril Bontédc0306e2015-03-02 00:08:40 +010024#endif
25
Willy Tarreau8d2b7772020-05-27 10:58:19 +020026#include <import/ebpttree.h>
Thierry FOURNIER380d0932015-01-23 14:27:52 +010027
Willy Tarreaub2551052020-06-09 09:07:15 +020028#include <haproxy/api.h>
29#include <haproxy/applet.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020030#include <haproxy/arg.h>
Christopher Fauletd25d9262020-08-06 11:04:46 +020031#include <haproxy/auth.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020032#include <haproxy/cfgparse.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020033#include <haproxy/channel.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020034#include <haproxy/cli.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020035#include <haproxy/connection.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020036#include <haproxy/h1.h>
Willy Tarreau86416052020-06-04 09:20:54 +020037#include <haproxy/hlua.h>
Willy Tarreau8c794002020-06-04 10:05:25 +020038#include <haproxy/hlua_fcn.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020039#include <haproxy/http_ana.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020040#include <haproxy/http_fetch.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/http_htx.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020042#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020043#include <haproxy/log.h>
Willy Tarreau2cd58092020-06-04 15:10:43 +020044#include <haproxy/map.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020045#include <haproxy/obj_type.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020046#include <haproxy/pattern.h>
Willy Tarreau469509b2020-06-04 15:13:30 +020047#include <haproxy/payload.h>
Willy Tarreau3d6ee402021-05-08 20:28:07 +020048#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020049#include <haproxy/regex.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020050#include <haproxy/sample.h>
Willy Tarreau198e92a2021-03-05 10:23:32 +010051#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +020052#include <haproxy/session.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020053#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020054#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020055#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020056#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020057#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020058#include <haproxy/thread.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020059#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020060#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020061#include <haproxy/xref.h>
62
Thierry FOURNIER380d0932015-01-23 14:27:52 +010063
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010064/* Lua uses longjmp to perform yield or throwing errors. This
65 * macro is used only for identifying the function that can
66 * not return because a longjmp is executed.
67 * __LJMP marks a prototype of hlua file that can use longjmp.
68 * WILL_LJMP() marks an lua function that will use longjmp.
69 * MAY_LJMP() marks an lua function that may use longjmp.
70 */
71#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020072#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010073#define MAY_LJMP(func) func
74
Thierry FOURNIERbabae282015-09-17 11:36:37 +020075/* This couple of function executes securely some Lua calls outside of
76 * the lua runtime environment. Each Lua call can return a longjmp
77 * if it encounter a memory error.
78 *
79 * Lua documentation extract:
80 *
81 * If an error happens outside any protected environment, Lua calls
82 * a panic function (see lua_atpanic) and then calls abort, thus
83 * exiting the host application. Your panic function can avoid this
84 * exit by never returning (e.g., doing a long jump to your own
85 * recovery point outside Lua).
86 *
87 * The panic function runs as if it were a message handler (see
88 * §2.3); in particular, the error message is at the top of the
89 * stack. However, there is no guarantee about stack space. To push
90 * anything on the stack, the panic function must first check the
91 * available space (see §4.2).
92 *
93 * We must check all the Lua entry point. This includes:
94 * - The include/proto/hlua.h exported functions
95 * - the task wrapper function
96 * - The action wrapper function
97 * - The converters wrapper function
98 * - The sample-fetch wrapper functions
99 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500100 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800101 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200102 *
103 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
104 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
105 * because they must be exists in the program stack when the longjmp
106 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200107 *
108 * Note that the Lua processing is not really thread safe. It provides
109 * heavy system which consists to add our own lock function in the Lua
110 * code and recompile the library. This system will probably not accepted
111 * by maintainers of various distribs.
112 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500113 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200114 * quick looking on the Lua sources displays a lua_lock() a the start
115 * of function and a lua_unlock() at the end of the function. So I
116 * conclude that the Lua thread safe mode just perform a mutex around
117 * all execution. So I prefer to do this in the HAProxy code, it will be
118 * easier for distro maintainers.
119 *
120 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
121 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
122 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200123 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100124__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200125THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200126static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau6a510902021-07-14 19:41:25 +0200127static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); return 0; }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200128
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100129/* This is the chained list of struct hlua_function referenced
130 * for haproxy action, sample-fetches, converters, cli and
131 * applet bindings. It is used for a post-initialisation control.
132 */
133static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
134
Thierry Fournierc7492592020-11-28 23:57:24 +0100135/* This variable is used only during initialization to identify the Lua state
136 * currently being initialized. 0 is the common lua state, 1 to n are the Lua
137 * states dedicated to each thread (in this case hlua_state_id==tid+1).
138 */
139static int hlua_state_id;
140
Thierry Fournier59f11be2020-11-29 00:37:41 +0100141/* This is a NULL-terminated list of lua file which are referenced to load per thread */
142static char **per_thread_load = NULL;
143
144lua_State *hlua_init_state(int thread_id);
145
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100146#define SET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200147 ({ \
148 int ret; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100149 if ((__HLUA)->state_id == 0) \
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100150 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200151 if (setjmp(safe_ljmp_env) != 0) { \
152 lua_atpanic(__L, hlua_panic_safe); \
153 ret = 0; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100154 if ((__HLUA)->state_id == 0) \
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100155 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200156 } else { \
157 lua_atpanic(__L, hlua_panic_ljmp); \
158 ret = 1; \
159 } \
160 ret; \
161 })
162
163/* If we are the last function catching Lua errors, we
164 * must reset the panic function.
165 */
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100166#define RESET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200167 do { \
168 lua_atpanic(__L, hlua_panic_safe); \
Thierry Fournier021d9862020-11-28 23:42:03 +0100169 if ((__HLUA)->state_id == 0) \
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100170 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200171 } while(0)
172
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100173#define SET_SAFE_LJMP(__HLUA) \
174 SET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
175
176#define RESET_SAFE_LJMP(__HLUA) \
177 RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
178
179#define SET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100180 SET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100181
182#define RESET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100183 RESET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100184
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200185/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200186#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100187/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200188#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200189/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100190#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100191#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200192
Thierry Fournierafc63e22020-11-28 17:06:51 +0100193/* The main Lua execution context. The 0 index is the
194 * common state shared by all threads.
195 */
Willy Tarreau186f3762020-12-04 11:48:12 +0100196static lua_State *hlua_states[MAX_THREADS + 1];
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100197
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100198/* This is the memory pool containing struct lua for applets
199 * (including cli).
200 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100201DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100202
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100203/* Used for Socket connection. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +0100204static struct proxy *socket_proxy;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100205static struct server *socket_tcp;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100206#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100207static struct server *socket_ssl;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100208#endif
209
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100210/* List head of the function called at the initialisation time. */
Thierry Fournierc7492592020-11-28 23:57:24 +0100211struct list hlua_init_functions[MAX_THREADS + 1];
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100212
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100213/* The following variables contains the reference of the different
214 * Lua classes. These references are useful for identify metadata
215 * associated with an object.
216 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100217static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100218static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100219static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100220static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100221static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100222static int class_http_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200223static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200224static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200225static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100226static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100227
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100228/* Global Lua execution timeout. By default Lua, execution linked
Willy Tarreau87b09662015-04-03 00:22:06 +0200229 * with stream (actions, sample-fetches and converters) have a
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100230 * short timeout. Lua linked with tasks doesn't have a timeout
231 * because a task may remain alive during all the haproxy execution.
232 */
233static unsigned int hlua_timeout_session = 4000; /* session timeout. */
234static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200235static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100236
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100237/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
238 * it is used for preventing infinite loops.
239 *
240 * I test the scheer with an infinite loop containing one incrementation
241 * and one test. I run this loop between 10 seconds, I raise a ceil of
242 * 710M loops from one interrupt each 9000 instructions, so I fix the value
243 * to one interrupt each 10 000 instructions.
244 *
245 * configured | Number of
246 * instructions | loops executed
247 * between two | in milions
248 * forced yields |
249 * ---------------+---------------
250 * 10 | 160
251 * 500 | 670
252 * 1000 | 680
253 * 5000 | 700
254 * 7000 | 700
255 * 8000 | 700
256 * 9000 | 710 <- ceil
257 * 10000 | 710
258 * 100000 | 710
259 * 1000000 | 710
260 *
261 */
262static unsigned int hlua_nb_instruction = 10000;
263
Willy Tarreaucdb53462020-12-02 12:12:00 +0100264/* Descriptor for the memory allocation state. The limit is pre-initialised to
265 * 0 until it is replaced by "tune.lua.maxmem" during the config parsing, or it
266 * is replaced with ~0 during post_init after everything was loaded. This way
267 * it is guaranteed that if limit is ~0 the boot is complete and that if it's
268 * zero it's not yet limited and proper accounting is required.
Willy Tarreau32f61e22015-03-18 17:54:59 +0100269 */
270struct hlua_mem_allocator {
271 size_t allocated;
272 size_t limit;
273};
274
Willy Tarreaucdb53462020-12-02 12:12:00 +0100275static struct hlua_mem_allocator hlua_global_allocator THREAD_ALIGNED(64);
Willy Tarreau32f61e22015-03-18 17:54:59 +0100276
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100277/* These functions converts types between HAProxy internal args or
278 * sample and LUA types. Another function permits to check if the
279 * LUA stack contains arguments according with an required ARG_T
280 * format.
281 */
282static int hlua_arg2lua(lua_State *L, const struct arg *arg);
283static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100284__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100285 uint64_t mask, struct proxy *p);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100286static int hlua_smp2lua(lua_State *L, struct sample *smp);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100287static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100288static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
289
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100290__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200291
Thierry Fournier59f11be2020-11-29 00:37:41 +0100292struct prepend_path {
293 struct list l;
294 char *type;
295 char *path;
296};
297
298static struct list prepend_path_list = LIST_HEAD_INIT(prepend_path_list);
299
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200300#define SEND_ERR(__be, __fmt, __args...) \
301 do { \
302 send_log(__be, LOG_ERR, __fmt, ## __args); \
303 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100304 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200305 } while (0)
306
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100307static inline struct hlua_function *new_hlua_function()
308{
309 struct hlua_function *fcn;
Thierry Fournierc7492592020-11-28 23:57:24 +0100310 int i;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100311
312 fcn = calloc(1, sizeof(*fcn));
313 if (!fcn)
314 return NULL;
Willy Tarreau2b718102021-04-21 07:32:39 +0200315 LIST_APPEND(&referenced_functions, &fcn->l);
Thierry Fournierc7492592020-11-28 23:57:24 +0100316 for (i = 0; i < MAX_THREADS + 1; i++)
317 fcn->function_ref[i] = -1;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100318 return fcn;
319}
320
Christopher Fauletdda44442021-04-12 14:05:43 +0200321static inline void release_hlua_function(struct hlua_function *fcn)
322{
323 if (!fcn)
324 return;
325 if (fcn->name)
326 ha_free(&fcn->name);
Willy Tarreau2b718102021-04-21 07:32:39 +0200327 LIST_DELETE(&fcn->l);
Christopher Fauletdda44442021-04-12 14:05:43 +0200328 ha_free(&fcn);
329}
330
Thierry Fournierc7492592020-11-28 23:57:24 +0100331/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
332static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
333{
334 if (fcn->function_ref[0] == -1)
335 return tid + 1;
336 return 0;
337}
338
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100339/* Used to check an Lua function type in the stack. It creates and
340 * returns a reference of the function. This function throws an
341 * error if the rgument is not a "function".
342 */
343__LJMP unsigned int hlua_checkfunction(lua_State *L, int argno)
344{
345 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100346 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100347 WILL_LJMP(luaL_argerror(L, argno, msg));
348 }
349 lua_pushvalue(L, argno);
350 return luaL_ref(L, LUA_REGISTRYINDEX);
351}
352
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100353/* Used to check an Lua table type in the stack. It creates and
354 * returns a reference of the table. This function throws an
355 * error if the rgument is not a "table".
356 */
357__LJMP unsigned int hlua_checktable(lua_State *L, int argno)
358{
359 if (!lua_istable(L, argno)) {
360 const char *msg = lua_pushfstring(L, "table expected, got %s", luaL_typename(L, argno));
361 WILL_LJMP(luaL_argerror(L, argno, msg));
362 }
363 lua_pushvalue(L, argno);
364 return luaL_ref(L, LUA_REGISTRYINDEX);
365}
366
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200367/* Return the string that is of the top of the stack. */
368const char *hlua_get_top_error_string(lua_State *L)
369{
370 if (lua_gettop(L) < 1)
371 return "unknown error";
372 if (lua_type(L, -1) != LUA_TSTRING)
373 return "unknown error";
374 return lua_tostring(L, -1);
375}
376
Christopher Fauletd09cc512021-03-24 14:48:45 +0100377__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200378{
379 lua_Debug ar;
380 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200381 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200382
383 while (lua_getstack(L, level++, &ar)) {
384
385 /* Add separator */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100386 if (b_data(msg))
387 chunk_appendf(msg, "%s", sep);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200388
389 /* Fill fields:
390 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
391 * 'l': fills in the field currentline;
392 * 'n': fills in the field name and namewhat;
393 * 't': fills in the field istailcall;
394 */
395 lua_getinfo(L, "Slnt", &ar);
396
397 /* Append code localisation */
398 if (ar.currentline > 0)
Christopher Fauletd09cc512021-03-24 14:48:45 +0100399 chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200400 else
Christopher Fauletd09cc512021-03-24 14:48:45 +0100401 chunk_appendf(msg, "%s: ", ar.short_src);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200402
403 /*
404 * Get function name
405 *
406 * if namewhat is no empty, name is defined.
407 * what contains "Lua" for Lua function, "C" for C function,
408 * or "main" for main code.
409 */
410 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100411 chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200412
413 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100414 chunk_appendf(msg, "in main chunk");
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200415
416 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100417 chunk_appendf(msg, "in function line %d", ar.linedefined);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200418
419 else /* nothing left... */
420 chunk_appendf(msg, "?");
421
422
423 /* Display tailed call */
424 if (ar.istailcall)
425 chunk_appendf(msg, " ...");
426 }
427
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200428 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200429}
430
431
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100432/* This function check the number of arguments available in the
433 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500434 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100435 */
436__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
437{
438 if (lua_gettop(L) == nb)
439 return;
440 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
441}
442
Mark Lakes22154b42018-01-29 14:38:40 -0800443/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100444 * and the line number where the error is encountered.
445 */
446static int hlua_pusherror(lua_State *L, const char *fmt, ...)
447{
448 va_list argp;
449 va_start(argp, fmt);
450 luaL_where(L, 1);
451 lua_pushvfstring(L, fmt, argp);
452 va_end(argp);
453 lua_concat(L, 2);
454 return 1;
455}
456
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100457/* This functions is used with sample fetch and converters. It
458 * converts the HAProxy configuration argument in a lua stack
459 * values.
460 *
461 * It takes an array of "arg", and each entry of the array is
462 * converted and pushed in the LUA stack.
463 */
464static int hlua_arg2lua(lua_State *L, const struct arg *arg)
465{
466 switch (arg->type) {
467 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100468 case ARGT_TIME:
469 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100470 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100471 break;
472
473 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200474 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100475 break;
476
477 case ARGT_IPV4:
478 case ARGT_IPV6:
479 case ARGT_MSK4:
480 case ARGT_MSK6:
481 case ARGT_FE:
482 case ARGT_BE:
483 case ARGT_TAB:
484 case ARGT_SRV:
485 case ARGT_USR:
486 case ARGT_MAP:
487 default:
488 lua_pushnil(L);
489 break;
490 }
491 return 1;
492}
493
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500494/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100495 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500496 * with sample fetch wrappers. The input arguments are given to the
497 * lua wrapper and converted as arg list by the function.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100498 */
499static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
500{
501 switch (lua_type(L, ud)) {
502
503 case LUA_TNUMBER:
504 case LUA_TBOOLEAN:
505 arg->type = ARGT_SINT;
506 arg->data.sint = lua_tointeger(L, ud);
507 break;
508
509 case LUA_TSTRING:
510 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200511 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200512 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200513 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200514 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100515 break;
516
517 case LUA_TUSERDATA:
518 case LUA_TNIL:
519 case LUA_TTABLE:
520 case LUA_TFUNCTION:
521 case LUA_TTHREAD:
522 case LUA_TLIGHTUSERDATA:
523 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200524 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100525 break;
526 }
527 return 1;
528}
529
530/* the following functions are used to convert a struct sample
531 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500532 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100533 */
Willy Tarreau5eadada2015-03-10 17:28:54 +0100534static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100535{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200536 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100537 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100538 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200539 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100540 break;
541
542 case SMP_T_BIN:
543 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200544 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100545 break;
546
547 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200548 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100549 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
550 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
551 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
552 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
553 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
554 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
555 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
556 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
557 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200558 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100559 break;
560 default:
561 lua_pushnil(L);
562 break;
563 }
564 break;
565
566 case SMP_T_IPV4:
567 case SMP_T_IPV6:
568 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200569 if (sample_casts[smp->data.type][SMP_T_STR] &&
570 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200571 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100572 else
573 lua_pushnil(L);
574 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100575 default:
576 lua_pushnil(L);
577 break;
578 }
579 return 1;
580}
581
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100582/* the following functions are used to convert a struct sample
583 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500584 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100585 */
586static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
587{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200588 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100589
590 case SMP_T_BIN:
591 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200592 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100593 break;
594
595 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200596 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100597 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
598 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
599 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
600 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
601 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
602 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
603 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
604 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
605 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200606 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100607 break;
608 default:
609 lua_pushstring(L, "");
610 break;
611 }
612 break;
613
614 case SMP_T_SINT:
615 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100616 case SMP_T_IPV4:
617 case SMP_T_IPV6:
618 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200619 if (sample_casts[smp->data.type][SMP_T_STR] &&
620 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200621 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100622 else
623 lua_pushstring(L, "");
624 break;
625 default:
626 lua_pushstring(L, "");
627 break;
628 }
629 return 1;
630}
631
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100632/* the following functions are used to convert an Lua type in a
633 * struct sample. This is useful to provide data from a converter
634 * to the LUA code.
635 */
636static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
637{
638 switch (lua_type(L, ud)) {
639
640 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200641 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200642 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100643 break;
644
645
646 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200647 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200648 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100649 break;
650
651 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200652 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100653 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200654 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200655 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200656 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200657 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100658 break;
659
660 case LUA_TUSERDATA:
661 case LUA_TNIL:
662 case LUA_TTABLE:
663 case LUA_TFUNCTION:
664 case LUA_TTHREAD:
665 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +0200666 case LUA_TNONE:
667 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200668 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200669 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100670 break;
671 }
672 return 1;
673}
674
Ilya Shipitsind4259502020-04-08 01:07:56 +0500675/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800676 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100677 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100678 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500679 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Willy Tarreauee0d7272021-07-16 10:26:56 +0200680 * entries and that there is at least one stop at the last position.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100681 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100682__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100683 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100684{
685 int min_arg;
Willy Tarreauee0d7272021-07-16 10:26:56 +0200686 int idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100687 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +0200688 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200689 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200690 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200691 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100692
693 idx = 0;
694 min_arg = ARGM(mask);
695 mask >>= ARGM_BITS;
696
697 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200698 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100699
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100700 /* Check for mandatory arguments. */
701 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100702 if (idx < min_arg) {
703
704 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200705 if (idx > 0) {
706 msg = "Mandatory argument expected";
707 goto error;
708 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100709
710 /* If first argument have a certain type, some default values
711 * may be used. See the function smp_resolve_args().
712 */
713 switch (mask & ARGT_MASK) {
714
715 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200716 if (!(p->cap & PR_CAP_FE)) {
717 msg = "Mandatory argument expected";
718 goto error;
719 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100720 argp[idx].data.prx = p;
721 argp[idx].type = ARGT_FE;
722 argp[idx+1].type = ARGT_STOP;
723 break;
724
725 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200726 if (!(p->cap & PR_CAP_BE)) {
727 msg = "Mandatory argument expected";
728 goto error;
729 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100730 argp[idx].data.prx = p;
731 argp[idx].type = ARGT_BE;
732 argp[idx+1].type = ARGT_STOP;
733 break;
734
735 case ARGT_TAB:
736 argp[idx].data.prx = p;
737 argp[idx].type = ARGT_TAB;
738 argp[idx+1].type = ARGT_STOP;
739 break;
740
741 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200742 msg = "Mandatory argument expected";
743 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100744 break;
745 }
746 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200747 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100748 }
749
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500750 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100751 if ((mask & ARGT_MASK) == ARGT_STOP &&
752 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200753 msg = "Last argument expected";
754 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100755 }
756
757 if ((mask & ARGT_MASK) == ARGT_STOP &&
758 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200759 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100760 }
761
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200762 /* Convert some argument types. All string in argp[] are for not
763 * duplicated yet.
764 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100765 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100766 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200767 if (argp[idx].type != ARGT_SINT) {
768 msg = "integer expected";
769 goto error;
770 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100771 argp[idx].type = ARGT_SINT;
772 break;
773
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100774 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200775 if (argp[idx].type != ARGT_SINT) {
776 msg = "integer expected";
777 goto error;
778 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200779 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100780 break;
781
782 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200783 if (argp[idx].type != ARGT_SINT) {
784 msg = "integer expected";
785 goto error;
786 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200787 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100788 break;
789
790 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200791 if (argp[idx].type != ARGT_STR) {
792 msg = "string expected";
793 goto error;
794 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200795 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200796 if (!argp[idx].data.prx) {
797 msg = "frontend doesn't exist";
798 goto error;
799 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100800 argp[idx].type = ARGT_FE;
801 break;
802
803 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200804 if (argp[idx].type != ARGT_STR) {
805 msg = "string expected";
806 goto error;
807 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200808 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200809 if (!argp[idx].data.prx) {
810 msg = "backend doesn't exist";
811 goto error;
812 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100813 argp[idx].type = ARGT_BE;
814 break;
815
816 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200817 if (argp[idx].type != ARGT_STR) {
818 msg = "string expected";
819 goto error;
820 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200821 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200822 if (!argp[idx].data.t) {
823 msg = "table doesn't exist";
824 goto error;
825 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100826 argp[idx].type = ARGT_TAB;
827 break;
828
829 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200830 if (argp[idx].type != ARGT_STR) {
831 msg = "string expected";
832 goto error;
833 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200834 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100835 if (sname) {
836 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200837 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +0200838 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200839 if (!px) {
840 msg = "backend doesn't exist";
841 goto error;
842 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100843 }
844 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200845 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100846 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100847 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100848 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200849 if (!argp[idx].data.srv) {
850 msg = "server doesn't exist";
851 goto error;
852 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100853 argp[idx].type = ARGT_SRV;
854 break;
855
856 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200857 if (argp[idx].type != ARGT_STR) {
858 msg = "string expected";
859 goto error;
860 }
861 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
862 msg = "invalid IPv4 address";
863 goto error;
864 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100865 argp[idx].type = ARGT_IPV4;
866 break;
867
868 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200869 if (argp[idx].type == ARGT_SINT)
870 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
871 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200872 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
873 msg = "invalid IPv4 mask";
874 goto error;
875 }
876 }
877 else {
878 msg = "integer or string expected";
879 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200880 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100881 argp[idx].type = ARGT_MSK4;
882 break;
883
884 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200885 if (argp[idx].type != ARGT_STR) {
886 msg = "string expected";
887 goto error;
888 }
889 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
890 msg = "invalid IPv6 address";
891 goto error;
892 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100893 argp[idx].type = ARGT_IPV6;
894 break;
895
896 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200897 if (argp[idx].type == ARGT_SINT)
898 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
899 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200900 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
901 msg = "invalid IPv6 mask";
902 goto error;
903 }
904 }
905 else {
906 msg = "integer or string expected";
907 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200908 }
Tim Duesterhusb814da62018-01-25 16:24:50 +0100909 argp[idx].type = ARGT_MSK6;
910 break;
911
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200912 case ARGT_REG:
913 if (argp[idx].type != ARGT_STR) {
914 msg = "string expected";
915 goto error;
916 }
917 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
918 if (!reg) {
919 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
920 argp[idx].data.str.area, err);
921 free(err);
922 goto error;
923 }
924 argp[idx].type = ARGT_REG;
925 argp[idx].data.reg = reg;
926 break;
927
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100928 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +0200929 if (argp[idx].type != ARGT_STR) {
930 msg = "string expected";
931 goto error;
932 }
933 if (p->uri_auth && p->uri_auth->userlist &&
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100934 strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area) == 0)
Christopher Fauletd25d9262020-08-06 11:04:46 +0200935 ul = p->uri_auth->userlist;
936 else
937 ul = auth_find_userlist(argp[idx].data.str.area);
938
939 if (!ul) {
940 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
941 goto error;
942 }
943 argp[idx].type = ARGT_USR;
944 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200945 break;
946
947 case ARGT_STR:
948 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
949 msg = "unable to duplicate string arg";
950 goto error;
951 }
952 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100953 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200954
Christopher Fauletd25d9262020-08-06 11:04:46 +0200955 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +0200956 msg = "type not yet supported";
957 goto error;
958 break;
959
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100960 }
961
962 /* Check for type of argument. */
963 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200964 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
965 arg_type_names[(mask & ARGT_MASK)],
966 arg_type_names[argp[idx].type & ARGT_MASK]);
967 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100968 }
969
970 /* Next argument. */
971 mask >>= ARGT_BITS;
972 idx++;
973 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200974 return 0;
975
976 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +0200977 free_args(argp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200978 WILL_LJMP(luaL_argerror(L, first + idx, msg));
979 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100980}
981
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100982/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500983 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100984 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100985 *
986 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100987 * - hlua_sethlua : create the association between hlua context and lua_state.
988 */
989static inline struct hlua *hlua_gethlua(lua_State *L)
990{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +0100991 struct hlua **hlua = lua_getextraspace(L);
992 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100993}
994static inline void hlua_sethlua(struct hlua *hlua)
995{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +0100996 struct hlua **hlua_store = lua_getextraspace(hlua->T);
997 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100998}
999
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001000/* This function is used to send logs. It try to send on screen (stderr)
1001 * and on the default syslog server.
1002 */
1003static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
1004{
1005 struct tm tm;
1006 char *p;
1007
1008 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001009 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001010 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001011 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +02001012 /* Break the message if exceed the buffer size. */
1013 *(p-4) = ' ';
1014 *(p-3) = '.';
1015 *(p-2) = '.';
1016 *(p-1) = '.';
1017 break;
1018 }
Willy Tarreau90807112020-02-25 08:16:33 +01001019 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001020 *p = *msg;
1021 else
1022 *p = '.';
1023 }
1024 *p = '\0';
1025
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001026 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001027 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +02001028 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
1029 return;
1030
Willy Tarreaua678b432015-08-28 10:14:59 +02001031 get_localtime(date.tv_sec, &tm);
1032 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001033 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001034 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001035 fflush(stderr);
1036 }
1037}
1038
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001039/* This function just ensure that the yield will be always
1040 * returned with a timeout and permit to set some flags
1041 */
1042__LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001043 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001044{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001045 struct hlua *hlua;
1046
1047 /* Get hlua struct, or NULL if we execute from main lua state */
1048 hlua = hlua_gethlua(L);
1049 if (!hlua) {
1050 return;
1051 }
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001052
1053 /* Set the wake timeout. If timeout is required, we set
1054 * the expiration time.
1055 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001056 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001057
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +01001058 hlua->flags |= flags;
1059
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001060 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +02001061 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001062}
1063
Willy Tarreau87b09662015-04-03 00:22:06 +02001064/* This function initialises the Lua environment stored in the stream.
1065 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001066 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001067 *
1068 * This function is particular. it initialises a new Lua thread. If the
1069 * initialisation fails (example: out of memory error), the lua function
1070 * throws an error (longjmp).
1071 *
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001072 * In some case (at least one), this function can be called from safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001073 * environment, so we must not initialise it. While the support of
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001074 * threads appear, the safe environment set a lock to ensure only one
1075 * Lua execution at a time. If we initialize safe environment in another
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001076 * safe environment, we have a dead lock.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001077 *
1078 * set "already_safe" true if the context is initialized form safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001079 * Lua function.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001080 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001081 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001082 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001083 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001084 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001085 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001086int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already_safe)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001087{
1088 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001089 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001090 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001091 lua->wake_time = TICK_ETERNITY;
Thierry Fournier021d9862020-11-28 23:42:03 +01001092 lua->state_id = state_id;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001093 LIST_INIT(&lua->com);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001094 if (!already_safe) {
1095 if (!SET_SAFE_LJMP_PARENT(lua)) {
1096 lua->Tref = LUA_REFNIL;
1097 return 0;
1098 }
1099 }
Thierry Fournier021d9862020-11-28 23:42:03 +01001100 lua->T = lua_newthread(hlua_states[state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001101 if (!lua->T) {
1102 lua->Tref = LUA_REFNIL;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001103 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001104 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001105 return 0;
1106 }
1107 hlua_sethlua(lua);
Thierry Fournier021d9862020-11-28 23:42:03 +01001108 lua->Tref = luaL_ref(hlua_states[state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001109 lua->task = task;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001110 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001111 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001112 return 1;
1113}
1114
Willy Tarreau87b09662015-04-03 00:22:06 +02001115/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001116 * is destroyed. The destroy also the memory context. The struct "lua"
1117 * is not freed.
1118 */
1119void hlua_ctx_destroy(struct hlua *lua)
1120{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001121 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001122 return;
1123
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001124 if (!lua->T)
1125 goto end;
1126
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001127 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001128 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001129
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001130 if (!SET_SAFE_LJMP(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001131 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001132 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001133 RESET_SAFE_LJMP(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001134
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001135 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001136 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001137 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001138 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001139 /* Forces a garbage collecting process. If the Lua program is finished
1140 * without error, we run the GC on the thread pointer. Its freed all
1141 * the unused memory.
1142 * If the thread is finnish with an error or is currently yielded,
1143 * it seems that the GC applied on the thread doesn't clean anything,
1144 * so e run the GC on the main thread.
1145 * NOTE: maybe this action locks all the Lua threads untiml the en of
1146 * the garbage collection.
1147 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001148 if (lua->gc_count) {
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001149 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001150 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001151 lua_gc(hlua_states[lua->state_id], LUA_GCCOLLECT, 0);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001152 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001153 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001154
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001155 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001156
1157end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001158 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001159}
1160
1161/* This function is used to restore the Lua context when a coroutine
1162 * fails. This function copy the common memory between old coroutine
1163 * and the new coroutine. The old coroutine is destroyed, and its
1164 * replaced by the new coroutine.
1165 * If the flag "keep_msg" is set, the last entry of the old is assumed
1166 * as string error message and it is copied in the new stack.
1167 */
1168static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1169{
1170 lua_State *T;
1171 int new_ref;
1172
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001173 /* New Lua coroutine. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001174 T = lua_newthread(hlua_states[lua->state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001175 if (!T)
1176 return 0;
1177
1178 /* Copy last error message. */
1179 if (keep_msg)
1180 lua_xmove(lua->T, T, 1);
1181
1182 /* Copy data between the coroutines. */
1183 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1184 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001185 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001186
1187 /* Destroy old data. */
1188 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1189
1190 /* The thread is garbage collected by Lua. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001191 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001192
1193 /* Fill the struct with the new coroutine values. */
1194 lua->Mref = new_ref;
1195 lua->T = T;
Thierry Fournier021d9862020-11-28 23:42:03 +01001196 lua->Tref = luaL_ref(hlua_states[lua->state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001197
1198 /* Set context. */
1199 hlua_sethlua(lua);
1200
1201 return 1;
1202}
1203
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001204void hlua_hook(lua_State *L, lua_Debug *ar)
1205{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001206 struct hlua *hlua;
1207
1208 /* Get hlua struct, or NULL if we execute from main lua state */
1209 hlua = hlua_gethlua(L);
1210 if (!hlua)
1211 return;
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001212
1213 /* Lua cannot yield when its returning from a function,
1214 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001215 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001216 */
1217 if (lua_gethookmask(L) & LUA_MASKRET) {
1218 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1219 return;
1220 }
1221
1222 /* restore the interrupt condition. */
1223 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1224
1225 /* If we interrupt the Lua processing in yieldable state, we yield.
1226 * If the state is not yieldable, trying yield causes an error.
1227 */
1228 if (lua_isyieldable(L))
Willy Tarreau9635e032018-10-16 17:52:55 +02001229 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001230
Thierry FOURNIERa85cfb12015-03-13 14:50:06 +01001231 /* If we cannot yield, update the clock and check the timeout. */
1232 tv_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001233 hlua->run_time += now_ms - hlua->start_time;
1234 if (hlua->max_time && hlua->run_time >= hlua->max_time) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001235 lua_pushfstring(L, "execution timeout");
1236 WILL_LJMP(lua_error(L));
1237 }
1238
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001239 /* Update the start time. */
1240 hlua->start_time = now_ms;
1241
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001242 /* Try to interrupt the process at the end of the current
1243 * unyieldable function.
1244 */
1245 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001246}
1247
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001248/* This function start or resumes the Lua stack execution. If the flag
1249 * "yield_allowed" if no set and the LUA stack execution returns a yield
1250 * The function return an error.
1251 *
1252 * The function can returns 4 values:
1253 * - HLUA_E_OK : The execution is terminated without any errors.
1254 * - HLUA_E_AGAIN : The execution must continue at the next associated
1255 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001256 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001257 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001258 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001259 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001260 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001261 * LUA code.
1262 */
1263static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1264{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001265#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1266 int nres;
1267#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001268 int ret;
1269 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001270 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001271
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001272 /* Initialise run time counter. */
1273 if (!HLUA_IS_RUNNING(lua))
1274 lua->run_time = 0;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001275
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001276 /* Lock the whole Lua execution. This lock must be before the
1277 * label "resume_execution".
1278 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001279 if (lua->state_id == 0)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001280 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001281
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001282resume_execution:
1283
1284 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1285 * instructions. it is used for preventing infinite loops.
1286 */
1287 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1288
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001289 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001290 HLUA_SET_RUN(lua);
1291 HLUA_CLR_CTRLYIELD(lua);
1292 HLUA_CLR_WAKERESWR(lua);
1293 HLUA_CLR_WAKEREQWR(lua);
Christopher Faulet1f43a342021-08-04 17:58:21 +02001294 HLUA_CLR_NOYIELD(lua);
1295 if (!yield_allowed)
1296 HLUA_SET_NOYIELD(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001297
Christopher Fauletbc275a92020-02-26 14:55:16 +01001298 /* Update the start time and reset wake_time. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001299 lua->start_time = now_ms;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001300 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001301
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001302 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001303#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournier021d9862020-11-28 23:42:03 +01001304 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs, &nres);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001305#else
Thierry Fournier021d9862020-11-28 23:42:03 +01001306 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001307#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001308 switch (ret) {
1309
1310 case LUA_OK:
1311 ret = HLUA_E_OK;
1312 break;
1313
1314 case LUA_YIELD:
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001315 /* Check if the execution timeout is expired. It it is the case, we
1316 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001317 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001318 tv_update_date(0, 1);
1319 lua->run_time += now_ms - lua->start_time;
1320 if (lua->max_time && lua->run_time > lua->max_time) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001321 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001322 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001323 break;
1324 }
1325 /* Process the forced yield. if the general yield is not allowed or
1326 * if no task were associated this the current Lua execution
1327 * coroutine, we resume the execution. Else we want to return in the
1328 * scheduler and we want to be waked up again, to continue the
1329 * current Lua execution. So we schedule our own task.
1330 */
1331 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001332 if (!yield_allowed || !lua->task)
1333 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001334 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001335 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001336 if (!yield_allowed) {
1337 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001338 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001339 break;
1340 }
1341 ret = HLUA_E_AGAIN;
1342 break;
1343
1344 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001345
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001346 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001347 * because the errors ares the only one mean to return immediately
1348 * from and lua execution.
1349 */
1350 if (lua->flags & HLUA_EXIT) {
1351 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001352 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001353 break;
1354 }
1355
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001356 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001357 if (!lua_checkstack(lua->T, 1)) {
1358 ret = HLUA_E_ERR;
1359 break;
1360 }
1361 msg = lua_tostring(lua->T, -1);
1362 lua_settop(lua->T, 0); /* Empty the stack. */
1363 lua_pop(lua->T, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01001364 trace = hlua_traceback(lua->T, ", ");
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001365 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001366 lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001367 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001368 lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001369 ret = HLUA_E_ERRMSG;
1370 break;
1371
1372 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001373 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001374 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001375 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001376 break;
1377
1378 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001379 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001380 if (!lua_checkstack(lua->T, 1)) {
1381 ret = HLUA_E_ERR;
1382 break;
1383 }
1384 msg = lua_tostring(lua->T, -1);
1385 lua_settop(lua->T, 0); /* Empty the stack. */
1386 lua_pop(lua->T, 1);
1387 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001388 lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001389 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001390 lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001391 ret = HLUA_E_ERRMSG;
1392 break;
1393
1394 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001395 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001396 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001397 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001398 break;
1399 }
1400
1401 switch (ret) {
1402 case HLUA_E_AGAIN:
1403 break;
1404
1405 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001406 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001407 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001408 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001409 break;
1410
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001411 case HLUA_E_ETMOUT:
1412 case HLUA_E_NOMEM:
1413 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001414 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001415 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001416 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001417 hlua_ctx_renew(lua, 0);
1418 break;
1419
1420 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001421 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001422 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001423 break;
1424 }
1425
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001426 /* This is the main exit point, remove the Lua lock. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001427 if (lua->state_id == 0)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001428 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001429
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001430 return ret;
1431}
1432
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001433/* This function exit the current code. */
1434__LJMP static int hlua_done(lua_State *L)
1435{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001436 struct hlua *hlua;
1437
1438 /* Get hlua struct, or NULL if we execute from main lua state */
1439 hlua = hlua_gethlua(L);
1440 if (!hlua)
1441 return 0;
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001442
1443 hlua->flags |= HLUA_EXIT;
1444 WILL_LJMP(lua_error(L));
1445
1446 return 0;
1447}
1448
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001449/* This function is an LUA binding. It provides a function
1450 * for deleting ACL from a referenced ACL file.
1451 */
1452__LJMP static int hlua_del_acl(lua_State *L)
1453{
1454 const char *name;
1455 const char *key;
1456 struct pat_ref *ref;
1457
1458 MAY_LJMP(check_args(L, 2, "del_acl"));
1459
1460 name = MAY_LJMP(luaL_checkstring(L, 1));
1461 key = MAY_LJMP(luaL_checkstring(L, 2));
1462
1463 ref = pat_ref_lookup(name);
1464 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001465 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001466
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001467 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001468 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001469 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001470 return 0;
1471}
1472
1473/* This function is an LUA binding. It provides a function
1474 * for deleting map entry from a referenced map file.
1475 */
1476static int hlua_del_map(lua_State *L)
1477{
1478 const char *name;
1479 const char *key;
1480 struct pat_ref *ref;
1481
1482 MAY_LJMP(check_args(L, 2, "del_map"));
1483
1484 name = MAY_LJMP(luaL_checkstring(L, 1));
1485 key = MAY_LJMP(luaL_checkstring(L, 2));
1486
1487 ref = pat_ref_lookup(name);
1488 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001489 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001490
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001491 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001492 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001493 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001494 return 0;
1495}
1496
1497/* This function is an LUA binding. It provides a function
1498 * for adding ACL pattern from a referenced ACL file.
1499 */
1500static int hlua_add_acl(lua_State *L)
1501{
1502 const char *name;
1503 const char *key;
1504 struct pat_ref *ref;
1505
1506 MAY_LJMP(check_args(L, 2, "add_acl"));
1507
1508 name = MAY_LJMP(luaL_checkstring(L, 1));
1509 key = MAY_LJMP(luaL_checkstring(L, 2));
1510
1511 ref = pat_ref_lookup(name);
1512 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001513 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001514
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001515 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001516 if (pat_ref_find_elt(ref, key) == NULL)
1517 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001518 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001519 return 0;
1520}
1521
1522/* This function is an LUA binding. It provides a function
1523 * for setting map pattern and sample from a referenced map
1524 * file.
1525 */
1526static int hlua_set_map(lua_State *L)
1527{
1528 const char *name;
1529 const char *key;
1530 const char *value;
1531 struct pat_ref *ref;
1532
1533 MAY_LJMP(check_args(L, 3, "set_map"));
1534
1535 name = MAY_LJMP(luaL_checkstring(L, 1));
1536 key = MAY_LJMP(luaL_checkstring(L, 2));
1537 value = MAY_LJMP(luaL_checkstring(L, 3));
1538
1539 ref = pat_ref_lookup(name);
1540 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001541 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001542
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001543 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001544 if (pat_ref_find_elt(ref, key) != NULL)
1545 pat_ref_set(ref, key, value, NULL);
1546 else
1547 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001548 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001549 return 0;
1550}
1551
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001552/* A class is a lot of memory that contain data. This data can be a table,
1553 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001554 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001555 * the name of the object (_G[<name>] = <metable> ).
1556 *
1557 * A metable is a table that modify the standard behavior of a standard
1558 * access to the associated data. The entries of this new metatable are
1559 * defined as is:
1560 *
1561 * http://lua-users.org/wiki/MetatableEvents
1562 *
1563 * __index
1564 *
1565 * we access an absent field in a table, the result is nil. This is
1566 * true, but it is not the whole truth. Actually, such access triggers
1567 * the interpreter to look for an __index metamethod: If there is no
1568 * such method, as usually happens, then the access results in nil;
1569 * otherwise, the metamethod will provide the result.
1570 *
1571 * Control 'prototype' inheritance. When accessing "myTable[key]" and
1572 * the key does not appear in the table, but the metatable has an __index
1573 * property:
1574 *
1575 * - if the value is a function, the function is called, passing in the
1576 * table and the key; the return value of that function is returned as
1577 * the result.
1578 *
1579 * - if the value is another table, the value of the key in that table is
1580 * asked for and returned (and if it doesn't exist in that table, but that
1581 * table's metatable has an __index property, then it continues on up)
1582 *
1583 * - Use "rawget(myTable,key)" to skip this metamethod.
1584 *
1585 * http://www.lua.org/pil/13.4.1.html
1586 *
1587 * __newindex
1588 *
1589 * Like __index, but control property assignment.
1590 *
1591 * __mode - Control weak references. A string value with one or both
1592 * of the characters 'k' and 'v' which specifies that the the
1593 * keys and/or values in the table are weak references.
1594 *
1595 * __call - Treat a table like a function. When a table is followed by
1596 * parenthesis such as "myTable( 'foo' )" and the metatable has
1597 * a __call key pointing to a function, that function is invoked
1598 * (passing any specified arguments) and the return value is
1599 * returned.
1600 *
1601 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
1602 * called, if the metatable for myTable has a __metatable
1603 * key, the value of that key is returned instead of the
1604 * actual metatable.
1605 *
1606 * __tostring - Control string representation. When the builtin
1607 * "tostring( myTable )" function is called, if the metatable
1608 * for myTable has a __tostring property set to a function,
1609 * that function is invoked (passing myTable to it) and the
1610 * return value is used as the string representation.
1611 *
1612 * __len - Control table length. When the table length is requested using
1613 * the length operator ( '#' ), if the metatable for myTable has
1614 * a __len key pointing to a function, that function is invoked
1615 * (passing myTable to it) and the return value used as the value
1616 * of "#myTable".
1617 *
1618 * __gc - Userdata finalizer code. When userdata is set to be garbage
1619 * collected, if the metatable has a __gc field pointing to a
1620 * function, that function is first invoked, passing the userdata
1621 * to it. The __gc metamethod is not called for tables.
1622 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
1623 *
1624 * Special metamethods for redefining standard operators:
1625 * http://www.lua.org/pil/13.1.html
1626 *
1627 * __add "+"
1628 * __sub "-"
1629 * __mul "*"
1630 * __div "/"
1631 * __unm "!"
1632 * __pow "^"
1633 * __concat ".."
1634 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001635 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001636 * http://www.lua.org/pil/13.2.html
1637 *
1638 * __eq "=="
1639 * __lt "<"
1640 * __le "<="
1641 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001642
1643/*
1644 *
1645 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001646 * Class Map
1647 *
1648 *
1649 */
1650
1651/* Returns a struct hlua_map if the stack entry "ud" is
1652 * a class session, otherwise it throws an error.
1653 */
1654__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
1655{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001656 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001657}
1658
1659/* This function is the map constructor. It don't need
1660 * the class Map object. It creates and return a new Map
1661 * object. It must be called only during "body" or "init"
1662 * context because it process some filesystem accesses.
1663 */
1664__LJMP static int hlua_map_new(struct lua_State *L)
1665{
1666 const char *fn;
1667 int match = PAT_MATCH_STR;
1668 struct sample_conv conv;
1669 const char *file = "";
1670 int line = 0;
1671 lua_Debug ar;
1672 char *err = NULL;
1673 struct arg args[2];
1674
1675 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
1676 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
1677
1678 fn = MAY_LJMP(luaL_checkstring(L, 1));
1679
1680 if (lua_gettop(L) >= 2) {
1681 match = MAY_LJMP(luaL_checkinteger(L, 2));
1682 if (match < 0 || match >= PAT_MATCH_NUM)
1683 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
1684 }
1685
1686 /* Get Lua filename and line number. */
1687 if (lua_getstack(L, 1, &ar)) { /* check function at level */
1688 lua_getinfo(L, "Sl", &ar); /* get info about it */
1689 if (ar.currentline > 0) { /* is there info? */
1690 file = ar.short_src;
1691 line = ar.currentline;
1692 }
1693 }
1694
1695 /* fill fake sample_conv struct. */
1696 conv.kw = ""; /* unused. */
1697 conv.process = NULL; /* unused. */
1698 conv.arg_mask = 0; /* unused. */
1699 conv.val_args = NULL; /* unused. */
1700 conv.out_type = SMP_T_STR;
1701 conv.private = (void *)(long)match;
1702 switch (match) {
1703 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
1704 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
1705 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
1706 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
1707 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
1708 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
1709 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001710 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001711 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
1712 default:
1713 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
1714 }
1715
1716 /* fill fake args. */
1717 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02001718 args[0].data.str.area = strdup(fn);
1719 args[0].data.str.data = strlen(fn);
1720 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001721 args[1].type = ARGT_STOP;
1722
1723 /* load the map. */
1724 if (!sample_load_map(args, &conv, file, line, &err)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001725 /* error case: we can't use luaL_error because we must
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001726 * free the err variable.
1727 */
1728 luaL_where(L, 1);
1729 lua_pushfstring(L, "'new': %s.", err);
1730 lua_concat(L, 2);
1731 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001732 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001733 WILL_LJMP(lua_error(L));
1734 }
1735
1736 /* create the lua object. */
1737 lua_newtable(L);
1738 lua_pushlightuserdata(L, args[0].data.map);
1739 lua_rawseti(L, -2, 0);
1740
1741 /* Pop a class Map metatable and affect it to the userdata. */
1742 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
1743 lua_setmetatable(L, -2);
1744
1745
1746 return 1;
1747}
1748
1749__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
1750{
1751 struct map_descriptor *desc;
1752 struct pattern *pat;
1753 struct sample smp;
1754
1755 MAY_LJMP(check_args(L, 2, "lookup"));
1756 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001757 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001758 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001759 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001760 }
1761 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001762 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001763 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001764 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 +01001765 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001766 }
1767
1768 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02001769 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001770 if (str)
1771 lua_pushstring(L, "");
1772 else
1773 lua_pushnil(L);
1774 return 1;
1775 }
1776
1777 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001778 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001779 return 1;
1780}
1781
1782__LJMP static int hlua_map_lookup(struct lua_State *L)
1783{
1784 return _hlua_map_lookup(L, 0);
1785}
1786
1787__LJMP static int hlua_map_slookup(struct lua_State *L)
1788{
1789 return _hlua_map_lookup(L, 1);
1790}
1791
1792/*
1793 *
1794 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001795 * Class Socket
1796 *
1797 *
1798 */
1799
1800__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
1801{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001802 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001803}
1804
1805/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001806 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001807 * received.
1808 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001809static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001810{
Willy Tarreau00a37f02015-04-13 12:05:19 +02001811 struct stream_interface *si = appctx->owner;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001812
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001813 if (appctx->ctx.hlua_cosocket.die) {
1814 si_shutw(si);
1815 si_shutr(si);
1816 si_ic(si)->flags |= CF_READ_NULL;
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001817 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1818 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001819 stream_shutdown(si_strm(si), SF_ERR_KILLED);
1820 }
1821
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001822 /* If we can't write, wakeup the pending write signals. */
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001823 if (channel_output_closed(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001824 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001825
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001826 /* If we can't read, wakeup the pending read signals. */
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001827 if (channel_input_closed(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001828 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001829
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001830 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001831 * to be notified whenever the connection completes.
1832 */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001833 if (si_opposite(si)->state < SI_ST_EST) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01001834 si_cant_get(si);
Willy Tarreau12c24232018-12-06 15:29:50 +01001835 si_rx_conn_blk(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01001836 si_rx_endp_more(si);
Willy Tarreaud4da1962015-04-20 01:31:23 +02001837 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001838 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001839
1840 /* This function is called after the connect. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01001841 appctx->ctx.hlua_cosocket.connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001842
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001843 /* Wake the tasks which wants to write if the buffer have available space. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001844 if (channel_may_recv(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001845 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001846
1847 /* Wake the tasks which wants to read if the buffer contains data. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001848 if (!channel_is_empty(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001849 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001850
1851 /* Some data were injected in the buffer, notify the stream
1852 * interface.
1853 */
1854 if (!channel_is_empty(si_ic(si)))
Willy Tarreau14bfe9a2018-12-19 15:19:27 +01001855 si_update(si);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001856
1857 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01001858 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001859 */
1860 if (notification_registered(&appctx->ctx.hlua_cosocket.wake_on_write))
Willy Tarreau3367d412018-11-15 10:57:41 +01001861 si_rx_endp_more(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001862}
1863
Willy Tarreau87b09662015-04-03 00:22:06 +02001864/* This function is called when the "struct stream" is destroyed.
1865 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001866 * Wake all the pending signals.
1867 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001868static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001869{
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001870 struct xref *peer;
1871
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001872 /* Remove my link in the original object. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001873 peer = xref_get_peer_and_lock(&appctx->ctx.hlua_cosocket.xref);
1874 if (peer)
1875 xref_disconnect(&appctx->ctx.hlua_cosocket.xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001876
1877 /* Wake all the task waiting for me. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001878 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1879 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001880}
1881
1882/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02001883 * uses this object. If the stream does not exists, just quit.
1884 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001885 * pending signal can rest in the read and write lists. destroy
1886 * it.
1887 */
1888__LJMP static int hlua_socket_gc(lua_State *L)
1889{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001890 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001891 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001892 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001893
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001894 MAY_LJMP(check_args(L, 1, "__gc"));
1895
1896 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001897 peer = xref_get_peer_and_lock(&socket->xref);
1898 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001899 return 0;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001900 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001901
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001902 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001903 appctx->ctx.hlua_cosocket.die = 1;
1904 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001905
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001906 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001907 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001908 return 0;
1909}
1910
1911/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02001912 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001913 */
sada05ed3302018-05-11 11:48:18 -07001914__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001915{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001916 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001917 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001918 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001919 struct hlua *hlua;
1920
1921 /* Get hlua struct, or NULL if we execute from main lua state */
1922 hlua = hlua_gethlua(L);
1923 if (!hlua)
1924 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001925
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001926 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02001927
1928 /* Check if we run on the same thread than the xreator thread.
1929 * We cannot access to the socket if the thread is different.
1930 */
1931 if (socket->tid != tid)
1932 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
1933
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001934 peer = xref_get_peer_and_lock(&socket->xref);
1935 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001936 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001937
1938 hlua->gc_count--;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001939 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001940
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001941 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001942 appctx->ctx.hlua_cosocket.die = 1;
1943 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001944
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001945 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001946 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001947 return 0;
1948}
1949
sada05ed3302018-05-11 11:48:18 -07001950/* The close function calls close_helper.
1951 */
1952__LJMP static int hlua_socket_close(lua_State *L)
1953{
1954 MAY_LJMP(check_args(L, 1, "close"));
1955 return hlua_socket_close_helper(L);
1956}
1957
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001958/* This Lua function assumes that the stack contain three parameters.
1959 * 1 - USERDATA containing a struct socket
1960 * 2 - INTEGER with values of the macro defined below
1961 * If the integer is -1, we must read at most one line.
1962 * If the integer is -2, we ust read all the data until the
1963 * end of the stream.
1964 * If the integer is positive value, we must read a number of
1965 * bytes corresponding to this value.
1966 */
1967#define HLSR_READ_LINE (-1)
1968#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001969__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001970{
1971 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
1972 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001973 struct hlua *hlua;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001974 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001975 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001976 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02001977 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001978 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02001979 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001980 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01001981 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01001982 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001983 struct stream_interface *si;
1984 struct stream *s;
1985 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02001986 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001987
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001988 /* Get hlua struct, or NULL if we execute from main lua state */
1989 hlua = hlua_gethlua(L);
1990
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001991 /* Check if this lua stack is schedulable. */
1992 if (!hlua || !hlua->task)
1993 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
1994 "'frontend', 'backend' or 'task'"));
1995
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02001996 /* Check if we run on the same thread than the xreator thread.
1997 * We cannot access to the socket if the thread is different.
1998 */
1999 if (socket->tid != tid)
2000 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2001
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002002 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002003 peer = xref_get_peer_and_lock(&socket->xref);
2004 if (!peer)
2005 goto no_peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002006 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2007 si = appctx->owner;
2008 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002009
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002010 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002011 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002012 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002013 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002014 if (nblk < 0) /* Connection close. */
2015 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002016 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002017 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002018
2019 /* remove final \r\n. */
2020 if (nblk == 1) {
2021 if (blk1[len1-1] == '\n') {
2022 len1--;
2023 skip_at_end++;
2024 if (blk1[len1-1] == '\r') {
2025 len1--;
2026 skip_at_end++;
2027 }
2028 }
2029 }
2030 else {
2031 if (blk2[len2-1] == '\n') {
2032 len2--;
2033 skip_at_end++;
2034 if (blk2[len2-1] == '\r') {
2035 len2--;
2036 skip_at_end++;
2037 }
2038 }
2039 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002040 }
2041
2042 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002043 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002044 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002045 if (nblk < 0) /* Connection close. */
2046 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002047 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002048 goto connection_empty;
2049 }
2050
2051 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002052 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002053 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002054 if (nblk < 0) /* Connection close. */
2055 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002056 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002057 goto connection_empty;
2058
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002059 missing_bytes = wanted - socket->b.n;
2060 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002061 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002062 len1 = missing_bytes;
2063 } if (nblk == 2 && len1 + len2 > missing_bytes)
2064 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002065 }
2066
2067 len = len1;
2068
2069 luaL_addlstring(&socket->b, blk1, len1);
2070 if (nblk == 2) {
2071 len += len2;
2072 luaL_addlstring(&socket->b, blk2, len2);
2073 }
2074
2075 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002076 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002077
2078 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002079 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002080
2081 /* If the pattern reclaim to read all the data
2082 * in the connection, got out.
2083 */
2084 if (wanted == HLSR_READ_ALL)
2085 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002086 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002087 goto connection_empty;
2088
2089 /* Return result. */
2090 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002091 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002092 return 1;
2093
2094connection_closed:
2095
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002096 xref_unlock(&socket->xref, peer);
2097
2098no_peer:
2099
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002100 /* If the buffer containds data. */
2101 if (socket->b.n > 0) {
2102 luaL_pushresult(&socket->b);
2103 return 1;
2104 }
2105 lua_pushnil(L);
2106 lua_pushstring(L, "connection closed.");
2107 return 2;
2108
2109connection_empty:
2110
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002111 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_read, hlua->task)) {
2112 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002113 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002114 }
2115 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002116 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002117 return 0;
2118}
2119
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002120/* This Lua function gets two parameters. The first one can be string
2121 * or a number. If the string is "*l", the user requires one line. If
2122 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002123 * If the value is a number, the user require a number of bytes equal
2124 * to the value. The default value is "*l" (a line).
2125 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002126 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002127 * integer takes this values:
2128 * -1 : read a line
2129 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002130 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002131 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002132 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002133 * concatenated with the read data.
2134 */
2135__LJMP static int hlua_socket_receive(struct lua_State *L)
2136{
2137 int wanted = HLSR_READ_LINE;
2138 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002139 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002140 char *error;
2141 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002142 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002143
2144 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2145 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2146
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002147 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002148
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002149 /* Check if we run on the same thread than the xreator thread.
2150 * We cannot access to the socket if the thread is different.
2151 */
2152 if (socket->tid != tid)
2153 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2154
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002155 /* check for pattern. */
2156 if (lua_gettop(L) >= 2) {
2157 type = lua_type(L, 2);
2158 if (type == LUA_TSTRING) {
2159 pattern = lua_tostring(L, 2);
2160 if (strcmp(pattern, "*a") == 0)
2161 wanted = HLSR_READ_ALL;
2162 else if (strcmp(pattern, "*l") == 0)
2163 wanted = HLSR_READ_LINE;
2164 else {
2165 wanted = strtoll(pattern, &error, 10);
2166 if (*error != '\0')
2167 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2168 }
2169 }
2170 else if (type == LUA_TNUMBER) {
2171 wanted = lua_tointeger(L, 2);
2172 if (wanted < 0)
2173 WILL_LJMP(luaL_error(L, "Unsupported size."));
2174 }
2175 }
2176
2177 /* Set pattern. */
2178 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002179
2180 /* Check if we would replace the top by itself. */
2181 if (lua_gettop(L) != 2)
2182 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002183
Christopher Fauletc31b2002021-05-03 10:11:13 +02002184 /* Save index of the top of the stack because since buffers are used, it
2185 * may change
2186 */
2187 lastarg = lua_gettop(L);
2188
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002189 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002190 luaL_buffinit(L, &socket->b);
2191
2192 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002193 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002194 if (lua_type(L, 3) != LUA_TSTRING)
2195 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2196 pattern = lua_tolstring(L, 3, &len);
2197 luaL_addlstring(&socket->b, pattern, len);
2198 }
2199
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002200 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002201}
2202
2203/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002204 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002205 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002206static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002207{
2208 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002209 struct hlua *hlua;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002210 struct appctx *appctx;
2211 size_t buf_len;
2212 const char *buf;
2213 int len;
2214 int send_len;
2215 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002216 struct xref *peer;
2217 struct stream_interface *si;
2218 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002219
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002220 /* Get hlua struct, or NULL if we execute from main lua state */
2221 hlua = hlua_gethlua(L);
2222
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002223 /* Check if this lua stack is schedulable. */
2224 if (!hlua || !hlua->task)
2225 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2226 "'frontend', 'backend' or 'task'"));
2227
2228 /* Get object */
2229 socket = MAY_LJMP(hlua_checksocket(L, 1));
2230 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002231 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002232
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002233 /* Check if we run on the same thread than the xreator thread.
2234 * We cannot access to the socket if the thread is different.
2235 */
2236 if (socket->tid != tid)
2237 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2238
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002239 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002240 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002241 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002242 lua_pushinteger(L, -1);
2243 return 1;
2244 }
2245 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2246 si = appctx->owner;
2247 s = si_strm(si);
2248
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002249 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002250 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002251 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002252 lua_pushinteger(L, -1);
2253 return 1;
2254 }
2255
2256 /* Update the input buffer data. */
2257 buf += sent;
2258 send_len = buf_len - sent;
2259
2260 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002261 if (sent >= buf_len) {
2262 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002263 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002264 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002265
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002266 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002267 * the request buffer if its not required.
2268 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002269 if (s->req.buf.size == 0) {
Willy Tarreau581abd32018-10-25 10:21:41 +02002270 if (!si_alloc_ibuf(si, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002271 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002272 }
2273
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002274 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002275 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002276 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002277 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002278 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002279
2280 /* send data */
2281 if (len < send_len)
2282 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002283 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002284
2285 /* "Not enough space" (-1), "Buffer too little to contain
2286 * the data" (-2) are not expected because the available length
2287 * is tested.
2288 * Other unknown error are also not expected.
2289 */
2290 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002291 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002292 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002293
sada05ed3302018-05-11 11:48:18 -07002294 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002295 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002296 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002297 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002298 return 1;
2299 }
2300
2301 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002302 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002303
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002304 s->req.rex = TICK_ETERNITY;
2305 s->res.wex = TICK_ETERNITY;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002306
2307 /* Update length sent. */
2308 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002309 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002310
2311 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002312 if (sent + len >= buf_len) {
2313 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002314 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002315 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002316
2317hlua_socket_write_yield_return:
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002318 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2319 xref_unlock(&socket->xref, peer);
2320 WILL_LJMP(luaL_error(L, "out of memory"));
2321 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002322 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002323 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002324 return 0;
2325}
2326
2327/* This function initiate the send of data. It just check the input
2328 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002329 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002330 * "hlua_socket_write_yield" that can yield.
2331 *
2332 * The Lua function gets between 3 and 4 parameters. The first one is
2333 * the associated object. The second is a string buffer. The third is
2334 * a facultative integer that represents where is the buffer position
2335 * of the start of the data that can send. The first byte is the
2336 * position "1". The default value is "1". The fourth argument is a
2337 * facultative integer that represents where is the buffer position
2338 * of the end of the data that can send. The default is the last byte.
2339 */
2340static int hlua_socket_send(struct lua_State *L)
2341{
2342 int i;
2343 int j;
2344 const char *buf;
2345 size_t buf_len;
2346
2347 /* Check number of arguments. */
2348 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2349 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2350
2351 /* Get the string. */
2352 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2353
2354 /* Get and check j. */
2355 if (lua_gettop(L) == 4) {
2356 j = MAY_LJMP(luaL_checkinteger(L, 4));
2357 if (j < 0)
2358 j = buf_len + j + 1;
2359 if (j > buf_len)
2360 j = buf_len + 1;
2361 lua_pop(L, 1);
2362 }
2363 else
2364 j = buf_len;
2365
2366 /* Get and check i. */
2367 if (lua_gettop(L) == 3) {
2368 i = MAY_LJMP(luaL_checkinteger(L, 3));
2369 if (i < 0)
2370 i = buf_len + i + 1;
2371 if (i > buf_len)
2372 i = buf_len + 1;
2373 lua_pop(L, 1);
2374 } else
2375 i = 1;
2376
2377 /* Check bth i and j. */
2378 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002379 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002380 return 1;
2381 }
2382 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002383 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002384 return 1;
2385 }
2386 if (i == 0)
2387 i = 1;
2388 if (j == 0)
2389 j = 1;
2390
2391 /* Pop the string. */
2392 lua_pop(L, 1);
2393
2394 /* Update the buffer length. */
2395 buf += i - 1;
2396 buf_len = j - i + 1;
2397 lua_pushlstring(L, buf, buf_len);
2398
2399 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002400 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002401
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002402 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002403}
2404
Willy Tarreau22b0a682015-06-17 19:43:49 +02002405#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002406__LJMP static inline int hlua_socket_info(struct lua_State *L, struct sockaddr_storage *addr)
2407{
2408 static char buffer[SOCKET_INFO_MAX_LEN];
2409 int ret;
2410 int len;
2411 char *p;
2412
2413 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2414 if (ret <= 0) {
2415 lua_pushnil(L);
2416 return 1;
2417 }
2418
2419 if (ret == AF_UNIX) {
2420 lua_pushstring(L, buffer+1);
2421 return 1;
2422 }
2423 else if (ret == AF_INET6) {
2424 buffer[0] = '[';
2425 len = strlen(buffer);
2426 buffer[len] = ']';
2427 len++;
2428 buffer[len] = ':';
2429 len++;
2430 p = buffer;
2431 }
2432 else if (ret == AF_INET) {
2433 p = buffer + 1;
2434 len = strlen(p);
2435 p[len] = ':';
2436 len++;
2437 }
2438 else {
2439 lua_pushnil(L);
2440 return 1;
2441 }
2442
2443 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2444 lua_pushnil(L);
2445 return 1;
2446 }
2447
2448 lua_pushstring(L, p);
2449 return 1;
2450}
2451
2452/* Returns information about the peer of the connection. */
2453__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2454{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002455 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002456 struct xref *peer;
2457 struct appctx *appctx;
2458 struct stream_interface *si;
2459 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002460 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002461
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002462 MAY_LJMP(check_args(L, 1, "getpeername"));
2463
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002464 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002465
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002466 /* Check if we run on the same thread than the xreator thread.
2467 * We cannot access to the socket if the thread is different.
2468 */
2469 if (socket->tid != tid)
2470 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2471
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002472 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002473 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002474 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002475 lua_pushnil(L);
2476 return 1;
2477 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002478 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2479 si = appctx->owner;
2480 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002481
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002482 if (!s->target_addr) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002483 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002484 lua_pushnil(L);
2485 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002486 }
2487
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002488 ret = MAY_LJMP(hlua_socket_info(L, s->target_addr));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002489 xref_unlock(&socket->xref, peer);
2490 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002491}
2492
2493/* Returns information about my connection side. */
2494static int hlua_socket_getsockname(struct lua_State *L)
2495{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002496 struct hlua_socket *socket;
2497 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002498 struct appctx *appctx;
2499 struct xref *peer;
2500 struct stream_interface *si;
2501 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002502 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002503
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002504 MAY_LJMP(check_args(L, 1, "getsockname"));
2505
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002506 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002507
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002508 /* Check if we run on the same thread than the xreator thread.
2509 * We cannot access to the socket if the thread is different.
2510 */
2511 if (socket->tid != tid)
2512 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2513
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002514 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002515 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002516 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002517 lua_pushnil(L);
2518 return 1;
2519 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002520 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2521 si = appctx->owner;
2522 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002523
Olivier Houchard9aaf7782017-09-13 18:30:23 +02002524 conn = cs_conn(objt_cs(s->si[1].end));
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002525 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002526 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002527 lua_pushnil(L);
2528 return 1;
2529 }
2530
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002531 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002532 xref_unlock(&socket->xref, peer);
2533 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002534}
2535
2536/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002537static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002538 .obj_type = OBJ_TYPE_APPLET,
2539 .name = "<LUA_TCP>",
2540 .fct = hlua_socket_handler,
2541 .release = hlua_socket_release,
2542};
2543
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002544__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002545{
2546 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002547 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002548 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002549 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002550 struct stream_interface *si;
2551 struct stream *s;
2552
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002553 /* Get hlua struct, or NULL if we execute from main lua state */
2554 hlua = hlua_gethlua(L);
2555 if (!hlua)
2556 return 0;
2557
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002558 /* Check if we run on the same thread than the xreator thread.
2559 * We cannot access to the socket if the thread is different.
2560 */
2561 if (socket->tid != tid)
2562 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2563
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002564 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002565 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002566 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002567 lua_pushnil(L);
2568 lua_pushstring(L, "Can't connect");
2569 return 2;
2570 }
2571 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2572 si = appctx->owner;
2573 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002574
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002575 /* Check if we run on the same thread than the xreator thread.
2576 * We cannot access to the socket if the thread is different.
2577 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002578 if (socket->tid != tid) {
2579 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002580 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002581 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002582
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002583 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002584 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002585 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002586 lua_pushnil(L);
2587 lua_pushstring(L, "Can't connect");
2588 return 2;
2589 }
2590
Willy Tarreaue09101e2018-10-16 17:37:12 +02002591 appctx = __objt_appctx(s->si[0].end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002592
2593 /* Check for connection established. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002594 if (appctx->ctx.hlua_cosocket.connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002595 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002596 lua_pushinteger(L, 1);
2597 return 1;
2598 }
2599
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002600 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2601 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002602 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002603 }
2604 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002605 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002606 return 0;
2607}
2608
2609/* This function fail or initite the connection. */
2610__LJMP static int hlua_socket_connect(struct lua_State *L)
2611{
2612 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002613 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002614 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002615 struct hlua *hlua;
2616 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002617 int low, high;
2618 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002619 struct xref *peer;
2620 struct stream_interface *si;
2621 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002622
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002623 if (lua_gettop(L) < 2)
2624 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002625
2626 /* Get args. */
2627 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002628
2629 /* 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 FOURNIER7e7ac322015-02-16 19:27:16 +01002635 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002636 if (lua_gettop(L) >= 3) {
2637 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002638 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002639
Tim Duesterhus6edab862018-01-06 19:04:45 +01002640 /* Force the ip to end with a colon, to support IPv6 addresses
2641 * that are not enclosed within square brackets.
2642 */
2643 if (port > 0) {
2644 luaL_buffinit(L, &b);
2645 luaL_addstring(&b, ip);
2646 luaL_addchar(&b, ':');
2647 luaL_pushresult(&b);
2648 ip = lua_tolstring(L, lua_gettop(L), NULL);
2649 }
2650 }
2651
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002652 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002653 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002654 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002655 lua_pushnil(L);
2656 return 1;
2657 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002658
2659 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002660 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 +02002661 if (!addr) {
2662 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002663 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002664 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002665
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002666 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002667 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002668 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002669 if (port == -1) {
2670 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002671 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002672 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002673 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2674 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002675 if (port == -1) {
2676 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002677 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002678 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002679 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002680 }
2681 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002682
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002683 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2684 si = appctx->owner;
2685 s = si_strm(si);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002686
Willy Tarreau9b7587a2020-10-15 07:32:10 +02002687 if (!sockaddr_alloc(&s->target_addr, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002688 xref_unlock(&socket->xref, peer);
2689 WILL_LJMP(luaL_error(L, "connect: internal error"));
2690 }
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002691 s->flags |= SF_ADDR_SET;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002692
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002693 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002694 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002695 if (!hlua)
2696 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002697
2698 /* inform the stream that we want to be notified whenever the
2699 * connection completes.
2700 */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01002701 si_cant_get(&s->si[0]);
Willy Tarreau3367d412018-11-15 10:57:41 +01002702 si_rx_endp_more(&s->si[0]);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002703 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002704
Willy Tarreauf31af932020-01-14 09:59:38 +01002705 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002706
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002707 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2708 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002709 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002710 }
2711 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002712
2713 task_wakeup(s->task, TASK_WOKEN_INIT);
2714 /* Return yield waiting for connection. */
2715
Willy Tarreau9635e032018-10-16 17:52:55 +02002716 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002717
2718 return 0;
2719}
2720
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002721#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002722__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
2723{
2724 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002725 struct xref *peer;
2726 struct appctx *appctx;
2727 struct stream_interface *si;
2728 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002729
2730 MAY_LJMP(check_args(L, 3, "connect_ssl"));
2731 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002732
2733 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002734 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002735 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002736 lua_pushnil(L);
2737 return 1;
2738 }
2739 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2740 si = appctx->owner;
2741 s = si_strm(si);
2742
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002743 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002744 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002745 return MAY_LJMP(hlua_socket_connect(L));
2746}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002747#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002748
2749__LJMP static int hlua_socket_setoption(struct lua_State *L)
2750{
2751 return 0;
2752}
2753
2754__LJMP static int hlua_socket_settimeout(struct lua_State *L)
2755{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002756 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002757 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02002758 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002759 struct xref *peer;
2760 struct appctx *appctx;
2761 struct stream_interface *si;
2762 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002763
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002764 MAY_LJMP(check_args(L, 2, "settimeout"));
2765
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002766 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02002767
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002768 /* convert the timeout to millis */
2769 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002770
Thierry Fournier17a921b2018-03-08 09:59:02 +01002771 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02002772 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01002773 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
2774
Mark Lakes56cc1252018-03-27 09:48:06 +02002775 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002776 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02002777
2778 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002779 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002780 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02002781
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002782 /* Check if we run on the same thread than the xreator thread.
2783 * We cannot access to the socket if the thread is different.
2784 */
2785 if (socket->tid != tid)
2786 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2787
Mark Lakes56cc1252018-03-27 09:48:06 +02002788 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002789 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002790 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002791 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
2792 WILL_LJMP(lua_error(L));
2793 return 0;
2794 }
2795 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2796 si = appctx->owner;
2797 s = si_strm(si);
2798
Cyril Bonté7bb63452018-08-17 23:51:02 +02002799 s->sess->fe->timeout.connect = tmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002800 s->req.rto = tmout;
2801 s->req.wto = tmout;
2802 s->res.rto = tmout;
2803 s->res.wto = tmout;
Cyril Bonté7bb63452018-08-17 23:51:02 +02002804 s->req.rex = tick_add_ifset(now_ms, tmout);
2805 s->req.wex = tick_add_ifset(now_ms, tmout);
2806 s->res.rex = tick_add_ifset(now_ms, tmout);
2807 s->res.wex = tick_add_ifset(now_ms, tmout);
2808
2809 s->task->expire = tick_add_ifset(now_ms, tmout);
2810 task_queue(s->task);
2811
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002812 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002813
Thierry Fourniere9636f12018-03-08 09:54:32 +01002814 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01002815 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002816}
2817
2818__LJMP static int hlua_socket_new(lua_State *L)
2819{
2820 struct hlua_socket *socket;
2821 struct appctx *appctx;
Willy Tarreau15b5e142015-04-04 14:38:25 +02002822 struct session *sess;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002823 struct stream *strm;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002824
2825 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002826 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002827 hlua_pusherror(L, "socket: full stack");
2828 goto out_fail_conf;
2829 }
2830
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002831 /* Create the object: obj[0] = userdata. */
2832 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002833 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002834 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002835 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002836 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002837
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002838 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01002839 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01002840 hlua_pusherror(L, "socket: uninitialized pools.");
2841 goto out_fail_conf;
2842 }
2843
Willy Tarreau87b09662015-04-03 00:22:06 +02002844 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002845 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
2846 lua_setmetatable(L, -2);
2847
Willy Tarreaud420a972015-04-06 00:39:18 +02002848 /* Create the applet context */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01002849 appctx = appctx_new(&update_applet, tid_bit);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002850 if (!appctx) {
2851 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaufeb76402015-04-03 14:10:06 +02002852 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002853 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002854
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002855 appctx->ctx.hlua_cosocket.connected = 0;
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002856 appctx->ctx.hlua_cosocket.die = 0;
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002857 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_write);
2858 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02002859
Willy Tarreaud420a972015-04-06 00:39:18 +02002860 /* Now create a session, task and stream for this applet */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01002861 sess = session_new(socket_proxy, NULL, &appctx->obj_type);
Willy Tarreaud420a972015-04-06 00:39:18 +02002862 if (!sess) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002863 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002864 goto out_fail_sess;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002865 }
2866
Christopher Faulet26256f82020-09-14 11:40:13 +02002867 strm = stream_new(sess, &appctx->obj_type, &BUF_NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002868 if (!strm) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002869 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002870 goto out_fail_stream;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002871 }
2872
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002873 /* Initialise cross reference between stream and Lua socket object. */
2874 xref_create(&socket->xref, &appctx->ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002875
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002876 /* Configure "right" stream interface. this "si" is used to connect
2877 * and retrieve data from the server. The connection is initialized
2878 * with the "struct server".
2879 */
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002880 si_set_state(&strm->si[1], SI_ST_ASS);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002881
2882 /* Force destination server. */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002883 strm->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002884 strm->target = &socket_tcp->obj_type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002885
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002886 return 1;
2887
Willy Tarreaud420a972015-04-06 00:39:18 +02002888 out_fail_stream:
Willy Tarreau11c36242015-04-04 15:54:03 +02002889 session_free(sess);
Willy Tarreaud420a972015-04-06 00:39:18 +02002890 out_fail_sess:
2891 appctx_free(appctx);
2892 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002893 WILL_LJMP(lua_error(L));
2894 return 0;
2895}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01002896
2897/*
2898 *
2899 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002900 * Class Channel
2901 *
2902 *
2903 */
2904
2905/* Returns the struct hlua_channel join to the class channel in the
2906 * stack entry "ud" or throws an argument error.
2907 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002908__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002909{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002910 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002911}
2912
Willy Tarreau47860ed2015-03-10 14:07:50 +01002913/* Pushes the channel onto the top of the stack. If the stask does not have a
2914 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002915 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01002916static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002917{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002918 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002919 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002920 return 0;
2921
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002922 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01002923 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002924 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002925
2926 /* Pop a class sesison metatable and affect it to the userdata. */
2927 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
2928 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002929 return 1;
2930}
2931
2932/* Duplicate all the data present in the input channel and put it
2933 * in a string LUA variables. Returns -1 and push a nil value in
2934 * the stack if the channel is closed and all the data are consumed,
2935 * returns 0 if no data are available, otherwise it returns the length
Ilya Shipitsind4259502020-04-08 01:07:56 +05002936 * of the built string.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002937 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002938static inline int _hlua_channel_dup(struct channel *chn, lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002939{
2940 char *blk1;
2941 char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002942 size_t len1;
2943 size_t len2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002944 int ret;
2945 luaL_Buffer b;
2946
Willy Tarreau06d80a92017-10-19 14:32:15 +02002947 ret = ci_getblk_nc(chn, &blk1, &len1, &blk2, &len2);
Christopher Faulet2e60aa42021-08-05 11:58:37 +02002948 if (unlikely(ret <= 0)) {
2949 if (ret < 0 || HLUA_CANT_YIELD(hlua_gethlua(L))) {
2950 lua_pushnil(L);
2951 return -1;
2952 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002953 return 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002954 }
2955
2956 luaL_buffinit(L, &b);
2957 luaL_addlstring(&b, blk1, len1);
2958 if (unlikely(ret == 2))
2959 luaL_addlstring(&b, blk2, len2);
2960 luaL_pushresult(&b);
2961
2962 if (unlikely(ret == 2))
2963 return len1 + len2;
2964 return len1;
2965}
2966
2967/* "_hlua_channel_dup" wrapper. If no data are available, it returns
2968 * a yield. This function keep the data in the buffer.
2969 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002970__LJMP static int hlua_channel_dup_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002971{
Willy Tarreau47860ed2015-03-10 14:07:50 +01002972 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002973
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002974 chn = MAY_LJMP(hlua_checkchannel(L, 1));
2975
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01002976 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02002977 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01002978 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02002979 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01002980
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002981 if (_hlua_channel_dup(chn, L) == 0)
Willy Tarreau9635e032018-10-16 17:52:55 +02002982 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_dup_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002983 return 1;
2984}
2985
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002986/* Check arguments for the function "hlua_channel_dup_yield". */
2987__LJMP static int hlua_channel_dup(lua_State *L)
2988{
2989 MAY_LJMP(check_args(L, 1, "dup"));
2990 MAY_LJMP(hlua_checkchannel(L, 1));
2991 return MAY_LJMP(hlua_channel_dup_yield(L, 0, 0));
2992}
2993
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002994/* "_hlua_channel_dup" wrapper. If no data are available, it returns
2995 * a yield. This function consumes the data in the buffer. It returns
2996 * a string containing the data or a nil pointer if no data are available
2997 * and the channel is closed.
2998 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002999__LJMP static int hlua_channel_get_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003000{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003001 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003002 int ret;
3003
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003004 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003005
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003006 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003007 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003008 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003009 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003010
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003011 ret = _hlua_channel_dup(chn, L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003012 if (unlikely(ret == 0))
Willy Tarreau9635e032018-10-16 17:52:55 +02003013 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_yield, TICK_ETERNITY, 0));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003014
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003015 if (unlikely(ret == -1))
3016 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003017
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003018 b_sub(&chn->buf, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003019 return 1;
3020}
3021
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003022/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003023__LJMP static int hlua_channel_get(lua_State *L)
3024{
3025 MAY_LJMP(check_args(L, 1, "get"));
3026 MAY_LJMP(hlua_checkchannel(L, 1));
3027 return MAY_LJMP(hlua_channel_get_yield(L, 0, 0));
3028}
3029
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003030/* This functions consumes and returns one line. If the channel is closed,
3031 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003032 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003033 * value.
3034 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003035__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003036{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003037 char *blk1;
3038 char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003039 size_t len1;
3040 size_t len2;
3041 size_t len;
Willy Tarreau47860ed2015-03-10 14:07:50 +01003042 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003043 int ret;
3044 luaL_Buffer b;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003045
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003046 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3047
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003048 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003049 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003050 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003051 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003052
Willy Tarreau06d80a92017-10-19 14:32:15 +02003053 ret = ci_getline_nc(chn, &blk1, &len1, &blk2, &len2);
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003054 if (ret == 0) {
3055 if (HLUA_CANT_YIELD(hlua_gethlua(L))) {
3056 _hlua_channel_dup(chn, L);
3057 return 1;
3058 }
Willy Tarreau9635e032018-10-16 17:52:55 +02003059 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003060 }
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003061
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003062 if (ret == -1) {
3063 lua_pushnil(L);
3064 return 1;
3065 }
3066
3067 luaL_buffinit(L, &b);
3068 luaL_addlstring(&b, blk1, len1);
3069 len = len1;
3070 if (unlikely(ret == 2)) {
3071 luaL_addlstring(&b, blk2, len2);
3072 len += len2;
3073 }
3074 luaL_pushresult(&b);
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003075 b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn) + len, NULL, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003076 return 1;
3077}
3078
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003079/* Check arguments for the function "hlua_channel_getline_yield". */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003080__LJMP static int hlua_channel_getline(lua_State *L)
3081{
3082 MAY_LJMP(check_args(L, 1, "getline"));
3083 MAY_LJMP(hlua_checkchannel(L, 1));
3084 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3085}
3086
Christopher Faulet23976d92021-08-06 09:59:49 +02003087/* This function takes a string as argument, and append it at the input side of
3088 * channel. If data cannot be copied, because there is not enough space to do so
3089 * or because the channel is closed, it returns -1. Otherwise, it returns the
3090 * amount of data written (the string length). This function does not yield.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003091 */
Christopher Faulet23976d92021-08-06 09:59:49 +02003092__LJMP static int hlua_channel_append(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003093{
Christopher Faulet23976d92021-08-06 09:59:49 +02003094 struct channel *chn;
3095 const char *str;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003096 size_t len;
Christopher Faulet23976d92021-08-06 09:59:49 +02003097
3098 MAY_LJMP(check_args(L, 2, "append"));
3099 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3100 str = MAY_LJMP(luaL_checklstring(L, 2, &len));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003101
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003102 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003103 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003104 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003105 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003106
Christopher Faulet23976d92021-08-06 09:59:49 +02003107 if (len > c_room(chn) || ci_putblk(chn, str, len) < 0)
3108 lua_pushinteger(L, -1);
3109 else
3110 lua_pushinteger(L, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003111 return 1;
3112}
3113
Christopher Faulet23976d92021-08-06 09:59:49 +02003114/* The function replaces input data from the channel by the string passed as
3115 * argument. Before clearing the buffer, we take care the copy will be
3116 * possible. It returns the amount of data written (the string length) on
3117 * success or -1 if the copy is not performed. This function does not yield.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003118 */
3119__LJMP static int hlua_channel_set(lua_State *L)
3120{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003121 struct channel *chn;
Christopher Faulet23976d92021-08-06 09:59:49 +02003122 const char *str;
3123 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003124
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003125 MAY_LJMP(check_args(L, 2, "set"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003126 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet23976d92021-08-06 09:59:49 +02003127 str = MAY_LJMP(luaL_checklstring(L, 2, &len));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003128
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003129 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003130 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003131 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003132 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003133
Christopher Faulet23976d92021-08-06 09:59:49 +02003134 /* Be sure we can copied the string once input data will be removed. */
3135 if (len > c_room(chn) + ci_data(chn) || channel_input_closed(chn))
3136 lua_pushinteger(L, -1);
3137 else {
3138 b_set_data(&chn->buf, co_data(chn));
3139 if (ci_putblk(chn, str, len) < 0)
3140 lua_pushinteger(L, -1);
3141 else
3142 lua_pushinteger(L, len);
3143 }
3144 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003145}
3146
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003147/* Append data in the output side of the buffer. This data is immediately
3148 * sent. The function returns the amount of data written. If the buffer
3149 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003150 * if the channel is closed.
3151 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003152__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003153{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003154 struct channel *chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003155 size_t len;
3156 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
3157 int l = MAY_LJMP(luaL_checkinteger(L, 3));
3158 int max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003159 struct hlua *hlua;
3160
3161 /* Get hlua struct, or NULL if we execute from main lua state */
3162 hlua = hlua_gethlua(L);
3163 if (!hlua) {
3164 lua_pushnil(L);
3165 return 1;
3166 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003167
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003168 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003169 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003170 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003171 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003172
Willy Tarreau47860ed2015-03-10 14:07:50 +01003173 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003174 lua_pushinteger(L, -1);
3175 return 1;
3176 }
3177
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003178 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003179 * the request buffer if its not required.
3180 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003181 if (chn->buf.size == 0) {
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003182 if (HLUA_CANT_YIELD(hlua_gethlua(L)))
3183 return 1;
Willy Tarreau4b962a42018-11-15 11:03:21 +01003184 si_rx_buff_blk(chn_prod(chn));
Willy Tarreau9635e032018-10-16 17:52:55 +02003185 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003186 }
3187
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003188 /* The written data will be immediately sent, so we can check
3189 * the available space without taking in account the reserve.
3190 * The reserve is guaranteed for the processing of incoming
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003191 * data, because the buffer will be flushed.
3192 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003193 max = b_room(&chn->buf);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003194
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003195 /* If there is no space available, and the output buffer is empty.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003196 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003197 * we return the amount of copied data.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003198 */
Willy Tarreaua79021a2018-06-15 18:07:57 +02003199 if (max == 0 && co_data(chn) == 0)
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003200 return 1;
3201
3202 /* Adjust the real required length. */
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003203 if (max > len - l)
3204 max = len - l;
3205
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003206 /* The buffer available size may be not contiguous. This test
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003207 * detects a non contiguous buffer and realign it.
3208 */
Willy Tarreau3f679992018-06-15 15:06:42 +02003209 if (ci_space_for_replace(chn) < max)
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003210 channel_slow_realign(chn, trash.area);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003211
3212 /* Copy input data in the buffer. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003213 max = b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn), str + l, max);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003214
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003215 /* buffer replace considers that the input part is filled.
3216 * so, I must forward these new data in the output part.
3217 */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02003218 c_adv(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003219
3220 l += max;
3221 lua_pop(L, 1);
3222 lua_pushinteger(L, l);
3223
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003224 if (l < len) {
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003225 /* If there is no space available, and the output buffer is empty.
3226 * in this case, we cannot add more data, so we cannot yield,
3227 * we return the amount of copied data.
3228 */
3229 max = b_room(&chn->buf);
3230 if ((max == 0 && co_data(chn) == 0) || HLUA_CANT_YIELD(hlua_gethlua(L)))
3231 return 1;
3232
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003233 /* If we are waiting for space in the response buffer, we
3234 * must set the flag WAKERESWR. This flag required the task
3235 * wake up if any activity is detected on the response buffer.
3236 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003237 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003238 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003239 else
3240 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003241 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003242 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003243
3244 return 1;
3245}
3246
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003247/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003248 * yield the LUA process, and resume it without checking the
3249 * input arguments.
3250 */
3251__LJMP static int hlua_channel_send(lua_State *L)
3252{
3253 MAY_LJMP(check_args(L, 2, "send"));
3254 lua_pushinteger(L, 0);
3255
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003256 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003257}
3258
3259/* This function forward and amount of butes. The data pass from
3260 * the input side of the buffer to the output side, and can be
3261 * forwarded. This function never fails.
3262 *
3263 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003264 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003265 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003266__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003267{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003268 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003269 int len;
3270 int l;
3271 int max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003272 struct hlua *hlua;
3273
3274 /* Get hlua struct, or NULL if we execute from main lua state */
3275 hlua = hlua_gethlua(L);
3276 if (!hlua)
3277 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003278
3279 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003280
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003281 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003282 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003283 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003284 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003285
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003286 len = MAY_LJMP(luaL_checkinteger(L, 2));
3287 l = MAY_LJMP(luaL_checkinteger(L, -1));
3288
3289 max = len - l;
Willy Tarreaua79021a2018-06-15 18:07:57 +02003290 if (max > ci_data(chn))
3291 max = ci_data(chn);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003292 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003293 l += max;
3294
3295 lua_pop(L, 1);
3296 lua_pushinteger(L, l);
3297
3298 /* Check if it miss bytes to forward. */
3299 if (l < len) {
3300 /* The the input channel or the output channel are closed, we
3301 * must return the amount of data forwarded.
3302 */
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003303 if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L)))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003304 return 1;
3305
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003306 /* If we are waiting for space data in the response buffer, we
3307 * must set the flag WAKERESWR. This flag required the task
3308 * wake up if any activity is detected on the response buffer.
3309 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003310 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003311 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003312 else
3313 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003314
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003315 /* Otherwise, we can yield waiting for new data in the inpout side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02003316 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003317 }
3318
3319 return 1;
3320}
3321
3322/* Just check the input and prepare the stack for the previous
3323 * function "hlua_channel_forward_yield"
3324 */
3325__LJMP static int hlua_channel_forward(lua_State *L)
3326{
3327 MAY_LJMP(check_args(L, 2, "forward"));
3328 MAY_LJMP(hlua_checkchannel(L, 1));
3329 MAY_LJMP(luaL_checkinteger(L, 2));
3330
3331 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003332 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003333}
3334
3335/* Just returns the number of bytes available in the input
3336 * side of the buffer. This function never fails.
3337 */
3338__LJMP static int hlua_channel_get_in_len(lua_State *L)
3339{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003340 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003341
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003342 MAY_LJMP(check_args(L, 1, "get_in_len"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003343 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta3ceac12018-12-14 13:39:09 +01003344 if (IS_HTX_STRM(chn_strm(chn))) {
3345 struct htx *htx = htxbuf(&chn->buf);
3346 lua_pushinteger(L, htx->data - co_data(chn));
3347 }
3348 else
3349 lua_pushinteger(L, ci_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003350 return 1;
3351}
3352
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003353/* Returns true if the channel is full. */
3354__LJMP static int hlua_channel_is_full(lua_State *L)
3355{
3356 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003357
3358 MAY_LJMP(check_args(L, 1, "is_full"));
3359 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01003360 /* ignore the reserve, we are not on a producer side (ie in an
3361 * applet).
3362 */
3363 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003364 return 1;
3365}
3366
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01003367/* Returns true if the channel is the response channel. */
3368__LJMP static int hlua_channel_is_resp(lua_State *L)
3369{
3370 struct channel *chn;
3371
3372 MAY_LJMP(check_args(L, 1, "is_resp"));
3373 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3374
3375 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
3376 return 1;
3377}
3378
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003379/* Just returns the number of bytes available in the output
3380 * side of the buffer. This function never fails.
3381 */
3382__LJMP static int hlua_channel_get_out_len(lua_State *L)
3383{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003384 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003385
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003386 MAY_LJMP(check_args(L, 1, "get_out_len"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003387 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Willy Tarreaua79021a2018-06-15 18:07:57 +02003388 lua_pushinteger(L, co_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003389 return 1;
3390}
3391
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003392/*
3393 *
3394 *
3395 * Class Fetches
3396 *
3397 *
3398 */
3399
3400/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003401 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003402 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003403__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003404{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003405 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003406}
3407
3408/* This function creates and push in the stack a fetch object according
3409 * with a current TXN.
3410 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003411static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003412{
Willy Tarreau7073c472015-04-06 11:15:40 +02003413 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003414
3415 /* Check stack size. */
3416 if (!lua_checkstack(L, 3))
3417 return 0;
3418
3419 /* Create the object: obj[0] = userdata.
3420 * Note that the base of the Fetches object is the
3421 * transaction object.
3422 */
3423 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003424 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003425 lua_rawseti(L, -2, 0);
3426
Willy Tarreau7073c472015-04-06 11:15:40 +02003427 hsmp->s = txn->s;
3428 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003429 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003430 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003431
3432 /* Pop a class sesison metatable and affect it to the userdata. */
3433 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
3434 lua_setmetatable(L, -2);
3435
3436 return 1;
3437}
3438
3439/* This function is an LUA binding. It is called with each sample-fetch.
3440 * It uses closure argument to store the associated sample-fetch. It
3441 * returns only one argument or throws an error. An error is thrown
3442 * only if an error is encountered during the argument parsing. If
3443 * the "sample-fetch" function fails, nil is returned.
3444 */
3445__LJMP static int hlua_run_sample_fetch(lua_State *L)
3446{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003447 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01003448 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003449 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003450 int i;
3451 struct sample smp;
3452
3453 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003454 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003455
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003456 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003457 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003458
Thierry FOURNIERca988662015-12-20 18:43:03 +01003459 /* Check execution authorization. */
3460 if (f->use & SMP_USE_HTTP_ANY &&
3461 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
3462 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
3463 "is not available in Lua services", f->kw);
3464 WILL_LJMP(lua_error(L));
3465 }
3466
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003467 /* Get extra arguments. */
3468 for (i = 0; i < lua_gettop(L) - 1; i++) {
3469 if (i >= ARGM_NBARGS)
3470 break;
3471 hlua_lua2arg(L, i + 2, &args[i]);
3472 }
3473 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003474 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003475
3476 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003477 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003478
3479 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01003480 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003481 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003482 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003483 }
3484
3485 /* Initialise the sample. */
3486 memset(&smp, 0, sizeof(smp));
3487
3488 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01003489 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02003490 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003491 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003492 lua_pushstring(L, "");
3493 else
3494 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003495 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003496 }
3497
3498 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003499 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003500 hlua_smp2lua_str(L, &smp);
3501 else
3502 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003503
3504 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003505 free_args(args);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003506 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003507
3508 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003509 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003510 WILL_LJMP(lua_error(L));
3511 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003512}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003513
3514/*
3515 *
3516 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003517 * Class Converters
3518 *
3519 *
3520 */
3521
3522/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003523 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003524 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003525__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003526{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003527 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003528}
3529
3530/* This function creates and push in the stack a Converters object
3531 * according with a current TXN.
3532 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003533static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003534{
Willy Tarreau7073c472015-04-06 11:15:40 +02003535 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003536
3537 /* Check stack size. */
3538 if (!lua_checkstack(L, 3))
3539 return 0;
3540
3541 /* Create the object: obj[0] = userdata.
3542 * Note that the base of the Converters object is the
3543 * same than the TXN object.
3544 */
3545 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003546 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003547 lua_rawseti(L, -2, 0);
3548
Willy Tarreau7073c472015-04-06 11:15:40 +02003549 hsmp->s = txn->s;
3550 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003551 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003552 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003553
Willy Tarreau87b09662015-04-03 00:22:06 +02003554 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003555 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
3556 lua_setmetatable(L, -2);
3557
3558 return 1;
3559}
3560
3561/* This function is an LUA binding. It is called with each converter.
3562 * It uses closure argument to store the associated converter. It
3563 * returns only one argument or throws an error. An error is thrown
3564 * only if an error is encountered during the argument parsing. If
3565 * the converter function function fails, nil is returned.
3566 */
3567__LJMP static int hlua_run_sample_conv(lua_State *L)
3568{
Willy Tarreauda5f1082015-04-06 11:17:13 +02003569 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003570 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003571 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003572 int i;
3573 struct sample smp;
3574
3575 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003576 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003577
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003578 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003579 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003580
3581 /* Get extra arguments. */
3582 for (i = 0; i < lua_gettop(L) - 2; i++) {
3583 if (i >= ARGM_NBARGS)
3584 break;
3585 hlua_lua2arg(L, i + 3, &args[i]);
3586 }
3587 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003588 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003589
3590 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003591 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003592
3593 /* Run the special args checker. */
3594 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
3595 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003596 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003597 }
3598
3599 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003600 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003601 if (!hlua_lua2smp(L, 2, &smp)) {
3602 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003603 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003604 }
3605
Willy Tarreau1777ea62016-03-10 16:15:46 +01003606 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
3607
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003608 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003609 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003610 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003611 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003612 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003613 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003614 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
3615 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003616 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003617 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003618 }
3619
3620 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02003621 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003622 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003623 lua_pushstring(L, "");
3624 else
Willy Tarreaua678b432015-08-28 10:14:59 +02003625 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003626 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003627 }
3628
3629 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003630 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003631 hlua_smp2lua_str(L, &smp);
3632 else
3633 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003634 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003635 free_args(args);
Willy Tarreaua678b432015-08-28 10:14:59 +02003636 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003637
3638 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003639 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003640 WILL_LJMP(lua_error(L));
3641 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003642}
3643
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003644/*
3645 *
3646 *
3647 * Class AppletTCP
3648 *
3649 *
3650 */
3651
3652/* Returns a struct hlua_txn if the stack entry "ud" is
3653 * a class stream, otherwise it throws an error.
3654 */
3655__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
3656{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003657 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003658}
3659
3660/* This function creates and push in the stack an Applet object
3661 * according with a current TXN.
3662 */
3663static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
3664{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003665 struct hlua_appctx *luactx;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003666 struct stream_interface *si = ctx->owner;
3667 struct stream *s = si_strm(si);
3668 struct proxy *p = s->be;
3669
3670 /* Check stack size. */
3671 if (!lua_checkstack(L, 3))
3672 return 0;
3673
3674 /* Create the object: obj[0] = userdata.
3675 * Note that the base of the Converters object is the
3676 * same than the TXN object.
3677 */
3678 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02003679 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003680 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02003681 luactx->appctx = ctx;
3682 luactx->htxn.s = s;
3683 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003684
3685 /* Create the "f" field that contains a list of fetches. */
3686 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003687 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003688 return 0;
3689 lua_settable(L, -3);
3690
3691 /* Create the "sf" field that contains a list of stringsafe fetches. */
3692 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003693 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003694 return 0;
3695 lua_settable(L, -3);
3696
3697 /* Create the "c" field that contains a list of converters. */
3698 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003699 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003700 return 0;
3701 lua_settable(L, -3);
3702
3703 /* Create the "sc" field that contains a list of stringsafe converters. */
3704 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003705 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003706 return 0;
3707 lua_settable(L, -3);
3708
3709 /* Pop a class stream metatable and affect it to the table. */
3710 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
3711 lua_setmetatable(L, -2);
3712
3713 return 1;
3714}
3715
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003716__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
3717{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003718 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003719 struct stream *s;
3720 const char *name;
3721 size_t len;
3722 struct sample smp;
3723
Tim Duesterhus4e172c92020-05-19 13:49:42 +02003724 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
3725 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003726
3727 /* It is useles to retrieve the stream, but this function
3728 * runs only in a stream context.
3729 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003730 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003731 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02003732 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003733
3734 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003735 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003736 hlua_lua2smp(L, 3, &smp);
3737
3738 /* Store the sample in a variable. */
3739 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02003740
3741 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
3742 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
3743 else
3744 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
3745
Tim Duesterhus84ebc132020-05-19 13:49:41 +02003746 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003747}
3748
3749__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
3750{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003751 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003752 struct stream *s;
3753 const char *name;
3754 size_t len;
3755 struct sample smp;
3756
3757 MAY_LJMP(check_args(L, 2, "unset_var"));
3758
3759 /* It is useles to retrieve the stream, but this function
3760 * runs only in a stream context.
3761 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003762 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003763 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02003764 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003765
3766 /* Unset the variable. */
3767 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02003768 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
3769 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003770}
3771
3772__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
3773{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003774 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003775 struct stream *s;
3776 const char *name;
3777 size_t len;
3778 struct sample smp;
3779
3780 MAY_LJMP(check_args(L, 2, "get_var"));
3781
3782 /* It is useles to retrieve the stream, but this function
3783 * runs only in a stream context.
3784 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003785 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003786 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02003787 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003788
3789 smp_set_owner(&smp, s->be, s->sess, s, 0);
3790 if (!vars_get_by_name(name, len, &smp)) {
3791 lua_pushnil(L);
3792 return 1;
3793 }
3794
3795 return hlua_smp2lua(L, &smp);
3796}
3797
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003798__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
3799{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003800 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3801 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01003802 struct hlua *hlua;
3803
3804 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01003805 if (!s->hlua)
3806 return 0;
3807 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003808
3809 MAY_LJMP(check_args(L, 2, "set_priv"));
3810
3811 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02003812 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003813
3814 /* Get and store new value. */
3815 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
3816 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
3817
3818 return 0;
3819}
3820
3821__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
3822{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003823 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3824 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01003825 struct hlua *hlua;
3826
3827 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01003828 if (!s->hlua) {
3829 lua_pushnil(L);
3830 return 1;
3831 }
3832 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003833
3834 /* Push configuration index in the stack. */
3835 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
3836
3837 return 1;
3838}
3839
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003840/* If expected data not yet available, it returns a yield. This function
3841 * consumes the data in the buffer. It returns a string containing the
3842 * data. This string can be empty.
3843 */
3844__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
3845{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003846 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3847 struct stream_interface *si = luactx->appctx->owner;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003848 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02003849 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003850 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02003851 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003852 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003853
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003854 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003855 ret = co_getline_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003856
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003857 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003858 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003859 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003860 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003861 }
3862
3863 /* End of data: commit the total strings and return. */
3864 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02003865 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003866 return 1;
3867 }
3868
3869 /* Ensure that the block 2 length is usable. */
3870 if (ret == 1)
3871 len2 = 0;
3872
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07003873 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003874 luaL_addlstring(&luactx->b, blk1, len1);
3875 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003876
3877 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003878 co_skip(si_oc(si), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02003879 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003880 return 1;
3881}
3882
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003883/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003884__LJMP static int hlua_applet_tcp_getline(lua_State *L)
3885{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003886 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003887
3888 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003889 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003890
3891 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
3892}
3893
3894/* If expected data not yet available, it returns a yield. This function
3895 * consumes the data in the buffer. It returns a string containing the
3896 * data. This string can be empty.
3897 */
3898__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
3899{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003900 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3901 struct stream_interface *si = luactx->appctx->owner;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003902 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003903 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02003904 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003905 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02003906 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003907 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003908
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003909 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003910 ret = co_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003911
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003912 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003913 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003914 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003915 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003916 }
3917
3918 /* End of data: commit the total strings and return. */
3919 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02003920 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003921 return 1;
3922 }
3923
3924 /* Ensure that the block 2 length is usable. */
3925 if (ret == 1)
3926 len2 = 0;
3927
3928 if (len == -1) {
3929
3930 /* If len == -1, catenate all the data avalaile and
3931 * yield because we want to get all the data until
3932 * the end of data stream.
3933 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003934 luaL_addlstring(&luactx->b, blk1, len1);
3935 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau06d80a92017-10-19 14:32:15 +02003936 co_skip(si_oc(si), len1 + len2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003937 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003938 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003939
3940 } else {
3941
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003942 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003943 if (len1 > len)
3944 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02003945 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003946 len -= len1;
3947
3948 /* Copy the second block. */
3949 if (len2 > len)
3950 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02003951 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003952 len -= len2;
3953
3954 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003955 co_skip(si_oc(si), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003956
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003957 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003958 if (len > 0) {
3959 lua_pushinteger(L, len);
3960 lua_replace(L, 2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003961 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003962 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003963 }
3964
3965 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003966 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003967 return 1;
3968 }
3969
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003970 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003971 hlua_pusherror(L, "Lua: internal error");
3972 WILL_LJMP(lua_error(L));
3973 return 0;
3974}
3975
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003976/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003977__LJMP static int hlua_applet_tcp_recv(lua_State *L)
3978{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003979 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003980 int len = -1;
3981
3982 if (lua_gettop(L) > 2)
3983 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
3984 if (lua_gettop(L) >= 2) {
3985 len = MAY_LJMP(luaL_checkinteger(L, 2));
3986 lua_pop(L, 1);
3987 }
3988
3989 /* Confirm or set the required length */
3990 lua_pushinteger(L, len);
3991
3992 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003993 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003994
3995 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
3996}
3997
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003998/* Append data in the output side of the buffer. This data is immediately
3999 * sent. The function returns the amount of data written. If the buffer
4000 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004001 * if the channel is closed.
4002 */
4003__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4004{
4005 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004006 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004007 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4008 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004009 struct stream_interface *si = luactx->appctx->owner;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004010 struct channel *chn = si_ic(si);
4011 int max;
4012
4013 /* Get the max amount of data which can write as input in the channel. */
4014 max = channel_recv_max(chn);
4015 if (max > (len - l))
4016 max = len - l;
4017
4018 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004019 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004020
4021 /* update counters. */
4022 l += max;
4023 lua_pop(L, 1);
4024 lua_pushinteger(L, l);
4025
4026 /* If some data is not send, declares the situation to the
4027 * applet, and returns a yield.
4028 */
4029 if (l < len) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004030 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004031 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004032 }
4033
4034 return 1;
4035}
4036
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004037/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004038 * yield the LUA process, and resume it without checking the
4039 * input arguments.
4040 */
4041__LJMP static int hlua_applet_tcp_send(lua_State *L)
4042{
4043 MAY_LJMP(check_args(L, 2, "send"));
4044 lua_pushinteger(L, 0);
4045
4046 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
4047}
4048
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004049/*
4050 *
4051 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004052 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004053 *
4054 *
4055 */
4056
4057/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004058 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004059 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004060__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004061{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004062 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004063}
4064
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004065/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004066 * according with a current TXN.
4067 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004068static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004069{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004070 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01004071 struct hlua_txn htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004072 struct stream_interface *si = ctx->owner;
4073 struct stream *s = si_strm(si);
4074 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02004075 struct htx *htx;
4076 struct htx_blk *blk;
4077 struct htx_sl *sl;
4078 struct ist path;
4079 unsigned long long len = 0;
4080 int32_t pos;
Amaury Denoyellec453f952021-07-06 11:40:12 +02004081 struct http_uri_parser parser;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004082
4083 /* Check stack size. */
4084 if (!lua_checkstack(L, 3))
4085 return 0;
4086
4087 /* Create the object: obj[0] = userdata.
4088 * Note that the base of the Converters object is the
4089 * same than the TXN object.
4090 */
4091 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004092 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004093 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004094 luactx->appctx = ctx;
4095 luactx->appctx->ctx.hlua_apphttp.status = 200; /* Default status code returned. */
4096 luactx->appctx->ctx.hlua_apphttp.reason = NULL; /* Use default reason based on status */
4097 luactx->htxn.s = s;
4098 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004099
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004100 /* Create the "f" field that contains a list of fetches. */
4101 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004102 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004103 return 0;
4104 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004105
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004106 /* Create the "sf" field that contains a list of stringsafe fetches. */
4107 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004108 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004109 return 0;
4110 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004111
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004112 /* Create the "c" field that contains a list of converters. */
4113 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004114 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004115 return 0;
4116 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004117
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004118 /* Create the "sc" field that contains a list of stringsafe converters. */
4119 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004120 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004121 return 0;
4122 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004123
Christopher Fauleta2097962019-07-15 16:25:33 +02004124 htx = htxbuf(&s->req.buf);
4125 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004126 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004127 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004128
Christopher Fauleta2097962019-07-15 16:25:33 +02004129 /* Stores the request method. */
4130 lua_pushstring(L, "method");
4131 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4132 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004133
Christopher Fauleta2097962019-07-15 16:25:33 +02004134 /* Stores the http version. */
4135 lua_pushstring(L, "version");
4136 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4137 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004138
Christopher Fauleta2097962019-07-15 16:25:33 +02004139 /* creates an array of headers. hlua_http_get_headers() crates and push
4140 * the array on the top of the stack.
4141 */
4142 lua_pushstring(L, "headers");
4143 htxn.s = s;
4144 htxn.p = px;
4145 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004146 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004147 return 0;
4148 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004149
Amaury Denoyellec453f952021-07-06 11:40:12 +02004150 parser = http_uri_parser_init(htx_sl_req_uri(sl));
4151 path = http_parse_path(&parser);
Tim Duesterhused526372020-03-05 17:56:33 +01004152 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004153 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004154
Christopher Fauleta2097962019-07-15 16:25:33 +02004155 p = path.ptr;
4156 end = path.ptr + path.len;
4157 q = p;
4158 while (q < end && *q != '?')
4159 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004160
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004161 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004162 lua_pushstring(L, "path");
4163 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004164 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004165
Christopher Fauleta2097962019-07-15 16:25:33 +02004166 /* Stores the query string. */
4167 lua_pushstring(L, "qs");
4168 if (*q == '?')
4169 q++;
4170 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004171 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004172 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004173
Christopher Fauleta2097962019-07-15 16:25:33 +02004174 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4175 struct htx_blk *blk = htx_get_blk(htx, pos);
4176 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004177
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004178 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02004179 break;
4180 if (type == HTX_BLK_DATA)
4181 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004182 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004183 if (htx->extra != ULLONG_MAX)
4184 len += htx->extra;
4185
4186 /* Stores the request path. */
4187 lua_pushstring(L, "length");
4188 lua_pushinteger(L, len);
4189 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004190
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004191 /* Create an empty array of HTTP request headers. */
4192 lua_pushstring(L, "response");
4193 lua_newtable(L);
4194 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004195
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004196 /* Pop a class stream metatable and affect it to the table. */
4197 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4198 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004199
4200 return 1;
4201}
4202
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004203__LJMP static int hlua_applet_http_set_var(lua_State *L)
4204{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004205 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004206 struct stream *s;
4207 const char *name;
4208 size_t len;
4209 struct sample smp;
4210
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004211 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4212 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004213
4214 /* It is useles to retrieve the stream, but this function
4215 * runs only in a stream context.
4216 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004217 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004218 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004219 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004220
4221 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004222 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004223 hlua_lua2smp(L, 3, &smp);
4224
4225 /* Store the sample in a variable. */
4226 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004227
4228 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4229 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4230 else
4231 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4232
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004233 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004234}
4235
4236__LJMP static int hlua_applet_http_unset_var(lua_State *L)
4237{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004238 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004239 struct stream *s;
4240 const char *name;
4241 size_t len;
4242 struct sample smp;
4243
4244 MAY_LJMP(check_args(L, 2, "unset_var"));
4245
4246 /* It is useles to retrieve the stream, but this function
4247 * runs only in a stream context.
4248 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004249 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004250 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004251 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004252
4253 /* Unset the variable. */
4254 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004255 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4256 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004257}
4258
4259__LJMP static int hlua_applet_http_get_var(lua_State *L)
4260{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004261 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004262 struct stream *s;
4263 const char *name;
4264 size_t len;
4265 struct sample smp;
4266
4267 MAY_LJMP(check_args(L, 2, "get_var"));
4268
4269 /* It is useles to retrieve the stream, but this function
4270 * runs only in a stream context.
4271 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004272 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004273 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004274 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004275
4276 smp_set_owner(&smp, s->be, s->sess, s, 0);
4277 if (!vars_get_by_name(name, len, &smp)) {
4278 lua_pushnil(L);
4279 return 1;
4280 }
4281
4282 return hlua_smp2lua(L, &smp);
4283}
4284
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004285__LJMP static int hlua_applet_http_set_priv(lua_State *L)
4286{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004287 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4288 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004289 struct hlua *hlua;
4290
4291 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004292 if (!s->hlua)
4293 return 0;
4294 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004295
4296 MAY_LJMP(check_args(L, 2, "set_priv"));
4297
4298 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004299 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004300
4301 /* Get and store new value. */
4302 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4303 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4304
4305 return 0;
4306}
4307
4308__LJMP static int hlua_applet_http_get_priv(lua_State *L)
4309{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004310 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4311 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004312 struct hlua *hlua;
4313
4314 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004315 if (!s->hlua) {
4316 lua_pushnil(L);
4317 return 1;
4318 }
4319 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004320
4321 /* Push configuration index in the stack. */
4322 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4323
4324 return 1;
4325}
4326
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004327/* If expected data not yet available, it returns a yield. This function
4328 * consumes the data in the buffer. It returns a string containing the
4329 * data. This string can be empty.
4330 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004331__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004332{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004333 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4334 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004335 struct channel *req = si_oc(si);
4336 struct htx *htx;
4337 struct htx_blk *blk;
4338 size_t count;
4339 int stop = 0;
4340
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004341 htx = htx_from_buf(&req->buf);
4342 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02004343 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01004344
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004345 while (count && !stop && blk) {
4346 enum htx_blk_type type = htx_get_blk_type(blk);
4347 uint32_t sz = htx_get_blksz(blk);
4348 struct ist v;
4349 uint32_t vlen;
4350 char *nl;
4351
4352 vlen = sz;
4353 if (vlen > count) {
4354 if (type != HTX_BLK_DATA)
4355 break;
4356 vlen = count;
4357 }
4358
4359 switch (type) {
4360 case HTX_BLK_UNUSED:
4361 break;
4362
4363 case HTX_BLK_DATA:
4364 v = htx_get_blk_value(htx, blk);
4365 v.len = vlen;
4366 nl = istchr(v, '\n');
4367 if (nl != NULL) {
4368 stop = 1;
4369 vlen = nl - v.ptr + 1;
4370 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02004371 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004372 break;
4373
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004374 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004375 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004376 stop = 1;
4377 break;
4378
4379 default:
4380 break;
4381 }
4382
4383 co_set_data(req, co_data(req) - vlen);
4384 count -= vlen;
4385 if (sz == vlen)
4386 blk = htx_remove_blk(htx, blk);
4387 else {
4388 htx_cut_data_blk(htx, blk, vlen);
4389 break;
4390 }
4391 }
4392
Christopher Fauleteccb31c2021-04-02 14:24:56 +02004393 /* The message was fully consumed and no more data are expected
4394 * (EOM flag set).
4395 */
4396 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4397 stop = 1;
4398
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004399 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004400 if (!stop) {
4401 si_cant_get(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004402 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004403 }
4404
4405 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004406 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004407 return 1;
4408}
4409
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004410
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004411/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004412__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004413{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004414 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004415
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004416 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004417 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004418
Christopher Fauleta2097962019-07-15 16:25:33 +02004419 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004420}
4421
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004422/* If expected data not yet available, it returns a yield. This function
4423 * consumes the data in the buffer. It returns a string containing the
4424 * data. This string can be empty.
4425 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004426__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004427{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004428 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4429 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004430 struct channel *req = si_oc(si);
4431 struct htx *htx;
4432 struct htx_blk *blk;
4433 size_t count;
4434 int len;
4435
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004436 htx = htx_from_buf(&req->buf);
4437 len = MAY_LJMP(luaL_checkinteger(L, 2));
4438 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02004439 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004440 while (count && len && blk) {
4441 enum htx_blk_type type = htx_get_blk_type(blk);
4442 uint32_t sz = htx_get_blksz(blk);
4443 struct ist v;
4444 uint32_t vlen;
4445
4446 vlen = sz;
4447 if (len > 0 && vlen > len)
4448 vlen = len;
4449 if (vlen > count) {
4450 if (type != HTX_BLK_DATA)
4451 break;
4452 vlen = count;
4453 }
4454
4455 switch (type) {
4456 case HTX_BLK_UNUSED:
4457 break;
4458
4459 case HTX_BLK_DATA:
4460 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004461 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004462 break;
4463
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004464 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004465 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004466 len = 0;
4467 break;
4468
4469 default:
4470 break;
4471 }
4472
4473 co_set_data(req, co_data(req) - vlen);
4474 count -= vlen;
4475 if (len > 0)
4476 len -= vlen;
4477 if (sz == vlen)
4478 blk = htx_remove_blk(htx, blk);
4479 else {
4480 htx_cut_data_blk(htx, blk, vlen);
4481 break;
4482 }
4483 }
4484
Christopher Fauleteccb31c2021-04-02 14:24:56 +02004485 /* The message was fully consumed and no more data are expected
4486 * (EOM flag set).
4487 */
4488 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4489 len = 0;
4490
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004491 htx_to_buf(htx, &req->buf);
4492
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004493 /* If we are no other data available, yield waiting for new data. */
4494 if (len) {
4495 if (len > 0) {
4496 lua_pushinteger(L, len);
4497 lua_replace(L, 2);
4498 }
4499 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004500 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004501 }
4502
4503 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004504 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004505 return 1;
4506}
4507
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004508/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004509__LJMP static int hlua_applet_http_recv(lua_State *L)
4510{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004511 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004512 int len = -1;
4513
4514 /* Check arguments. */
4515 if (lua_gettop(L) > 2)
4516 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4517 if (lua_gettop(L) >= 2) {
4518 len = MAY_LJMP(luaL_checkinteger(L, 2));
4519 lua_pop(L, 1);
4520 }
4521
Christopher Fauleta2097962019-07-15 16:25:33 +02004522 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004523
Christopher Fauleta2097962019-07-15 16:25:33 +02004524 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004525 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004526
Christopher Fauleta2097962019-07-15 16:25:33 +02004527 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004528}
4529
4530/* Append data in the output side of the buffer. This data is immediately
4531 * sent. The function returns the amount of data written. If the buffer
4532 * cannot contain the data, the function yields. The function returns -1
4533 * if the channel is closed.
4534 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004535__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004536{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004537 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4538 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004539 struct channel *res = si_ic(si);
4540 struct htx *htx = htx_from_buf(&res->buf);
4541 const char *data;
4542 size_t len;
4543 int l = MAY_LJMP(luaL_checkinteger(L, 3));
4544 int max;
4545
Christopher Faulet9060fc02019-07-03 11:39:30 +02004546 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004547 if (!max)
4548 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004549
4550 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
4551
4552 /* Get the max amount of data which can write as input in the channel. */
4553 if (max > (len - l))
4554 max = len - l;
4555
4556 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02004557 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004558 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004559
4560 /* update counters. */
4561 l += max;
4562 lua_pop(L, 1);
4563 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004564
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004565 /* If some data is not send, declares the situation to the
4566 * applet, and returns a yield.
4567 */
4568 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004569 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004570 htx_to_buf(htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004571 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004572 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004573 }
4574
Christopher Fauleta2097962019-07-15 16:25:33 +02004575 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004576 return 1;
4577}
4578
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004579/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004580 * yield the LUA process, and resume it without checking the
4581 * input arguments.
4582 */
4583__LJMP static int hlua_applet_http_send(lua_State *L)
4584{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004585 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004586
4587 /* We want to send some data. Headers must be sent. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004588 if (!(luactx->appctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004589 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
4590 WILL_LJMP(lua_error(L));
4591 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004592
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004593 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004594 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004595
Christopher Fauleta2097962019-07-15 16:25:33 +02004596 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004597}
4598
4599__LJMP static int hlua_applet_http_addheader(lua_State *L)
4600{
4601 const char *name;
4602 int ret;
4603
4604 MAY_LJMP(hlua_checkapplet_http(L, 1));
4605 name = MAY_LJMP(luaL_checkstring(L, 2));
4606 MAY_LJMP(luaL_checkstring(L, 3));
4607
4608 /* Push in the stack the "response" entry. */
4609 ret = lua_getfield(L, 1, "response");
4610 if (ret != LUA_TTABLE) {
4611 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
4612 "is expected as an array. %s found", lua_typename(L, ret));
4613 WILL_LJMP(lua_error(L));
4614 }
4615
4616 /* check if the header is already registered if it is not
4617 * the case, register it.
4618 */
4619 ret = lua_getfield(L, -1, name);
4620 if (ret == LUA_TNIL) {
4621
4622 /* Entry not found. */
4623 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
4624
4625 /* Insert the new header name in the array in the top of the stack.
4626 * It left the new array in the top of the stack.
4627 */
4628 lua_newtable(L);
4629 lua_pushvalue(L, 2);
4630 lua_pushvalue(L, -2);
4631 lua_settable(L, -4);
4632
4633 } else if (ret != LUA_TTABLE) {
4634
4635 /* corruption error. */
4636 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
4637 "is expected as an array. %s found", name, lua_typename(L, ret));
4638 WILL_LJMP(lua_error(L));
4639 }
4640
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004641 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004642 * the header value as new entry.
4643 */
4644 lua_pushvalue(L, 3);
4645 ret = lua_rawlen(L, -2);
4646 lua_rawseti(L, -2, ret + 1);
4647 lua_pushboolean(L, 1);
4648 return 1;
4649}
4650
4651__LJMP static int hlua_applet_http_status(lua_State *L)
4652{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004653 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004654 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08004655 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004656
4657 if (status < 100 || status > 599) {
4658 lua_pushboolean(L, 0);
4659 return 1;
4660 }
4661
Willy Tarreau7e702d12021-04-28 17:59:21 +02004662 luactx->appctx->ctx.hlua_apphttp.status = status;
4663 luactx->appctx->ctx.hlua_apphttp.reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004664 lua_pushboolean(L, 1);
4665 return 1;
4666}
4667
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004668
Christopher Fauleta2097962019-07-15 16:25:33 +02004669__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004670{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004671 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4672 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004673 struct channel *res = si_ic(si);
4674 struct htx *htx;
4675 struct htx_sl *sl;
4676 struct h1m h1m;
4677 const char *status, *reason;
4678 const char *name, *value;
4679 size_t nlen, vlen;
4680 unsigned int flags;
4681
4682 /* Send the message at once. */
4683 htx = htx_from_buf(&res->buf);
4684 h1m_init_res(&h1m);
4685
4686 /* Use the same http version than the request. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004687 status = ultoa_r(luactx->appctx->ctx.hlua_apphttp.status, trash.area, trash.size);
4688 reason = luactx->appctx->ctx.hlua_apphttp.reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004689 if (reason == NULL)
Willy Tarreau7e702d12021-04-28 17:59:21 +02004690 reason = http_get_reason(luactx->appctx->ctx.hlua_apphttp.status);
4691 if (luactx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004692 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
4693 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
4694 }
4695 else {
4696 flags = HTX_SL_F_IS_RESP;
4697 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
4698 }
4699 if (!sl) {
4700 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004701 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004702 WILL_LJMP(lua_error(L));
4703 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02004704 sl->info.res.status = luactx->appctx->ctx.hlua_apphttp.status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004705
4706 /* Get the array associated to the field "response" in the object AppletHTTP. */
4707 lua_pushvalue(L, 0);
4708 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
4709 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004710 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004711 WILL_LJMP(lua_error(L));
4712 }
4713
4714 /* Browse the list of headers. */
4715 lua_pushnil(L);
4716 while(lua_next(L, -2) != 0) {
4717 /* We expect a string as -2. */
4718 if (lua_type(L, -2) != LUA_TSTRING) {
4719 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004720 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004721 lua_typename(L, lua_type(L, -2)));
4722 WILL_LJMP(lua_error(L));
4723 }
4724 name = lua_tolstring(L, -2, &nlen);
4725
4726 /* We expect an array as -1. */
4727 if (lua_type(L, -1) != LUA_TTABLE) {
4728 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 +02004729 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004730 name,
4731 lua_typename(L, lua_type(L, -1)));
4732 WILL_LJMP(lua_error(L));
4733 }
4734
4735 /* Browse the table who is on the top of the stack. */
4736 lua_pushnil(L);
4737 while(lua_next(L, -2) != 0) {
4738 int id;
4739
4740 /* We expect a number as -2. */
4741 if (lua_type(L, -2) != LUA_TNUMBER) {
4742 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 +02004743 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004744 name,
4745 lua_typename(L, lua_type(L, -2)));
4746 WILL_LJMP(lua_error(L));
4747 }
4748 id = lua_tointeger(L, -2);
4749
4750 /* We expect a string as -2. */
4751 if (lua_type(L, -1) != LUA_TSTRING) {
4752 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 +02004753 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004754 name, id,
4755 lua_typename(L, lua_type(L, -1)));
4756 WILL_LJMP(lua_error(L));
4757 }
4758 value = lua_tolstring(L, -1, &vlen);
4759
4760 /* Simple Protocol checks. */
4761 if (isteqi(ist2(name, nlen), ist("transfer-encoding")))
Christopher Faulet700d9e82020-01-31 12:21:52 +01004762 h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004763 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
4764 struct ist v = ist2(value, vlen);
4765 int ret;
4766
4767 ret = h1_parse_cont_len_header(&h1m, &v);
4768 if (ret < 0) {
4769 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004770 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004771 name);
4772 WILL_LJMP(lua_error(L));
4773 }
4774 else if (ret == 0)
4775 goto next; /* Skip it */
4776 }
4777
4778 /* Add a new header */
4779 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
4780 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004781 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004782 name);
4783 WILL_LJMP(lua_error(L));
4784 }
4785 next:
4786 /* Remove the array from the stack, and get next element with a remaining string. */
4787 lua_pop(L, 1);
4788 }
4789
4790 /* Remove the array from the stack, and get next element with a remaining string. */
4791 lua_pop(L, 1);
4792 }
4793
4794 if (h1m.flags & H1_MF_CHNK)
4795 h1m.flags &= ~H1_MF_CLEN;
4796 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
4797 h1m.flags |= H1_MF_XFER_LEN;
4798
4799 /* Uset HTX start-line flags */
4800 if (h1m.flags & H1_MF_XFER_ENC)
4801 flags |= HTX_SL_F_XFER_ENC;
4802 if (h1m.flags & H1_MF_XFER_LEN) {
4803 flags |= HTX_SL_F_XFER_LEN;
4804 if (h1m.flags & H1_MF_CHNK)
4805 flags |= HTX_SL_F_CHNK;
4806 else if (h1m.flags & H1_MF_CLEN)
4807 flags |= HTX_SL_F_CLEN;
4808 if (h1m.body_len == 0)
4809 flags |= HTX_SL_F_BODYLESS;
4810 }
4811 sl->flags |= flags;
4812
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004813 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004814 * and the status code implies the presence of a message body, we must
4815 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004816 * for the keepalive compliance. If the applet announces a transfer-encoding
4817 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004818 */
4819 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreau7e702d12021-04-28 17:59:21 +02004820 luactx->appctx->ctx.hlua_apphttp.status >= 200 &&
4821 luactx->appctx->ctx.hlua_apphttp.status != 204 &&
4822 luactx->appctx->ctx.hlua_apphttp.status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004823 /* Add a new header */
4824 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
4825 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
4826 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004827 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004828 WILL_LJMP(lua_error(L));
4829 }
4830 }
4831
4832 /* Finalize headers. */
4833 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
4834 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004835 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004836 WILL_LJMP(lua_error(L));
4837 }
4838
4839 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
4840 b_reset(&res->buf);
4841 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
4842 WILL_LJMP(lua_error(L));
4843 }
4844
4845 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004846 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004847
4848 /* Headers sent, set the flag. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004849 luactx->appctx->ctx.hlua_apphttp.flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004850 return 0;
4851
4852}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004853/* We will build the status line and the headers of the HTTP response.
4854 * We will try send at once if its not possible, we give back the hand
4855 * waiting for more room.
4856 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004857__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004858{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004859 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4860 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004861 struct channel *res = si_ic(si);
4862
4863 if (co_data(res)) {
4864 si_rx_room_blk(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004865 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004866 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004867 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004868}
4869
4870
Christopher Fauleta2097962019-07-15 16:25:33 +02004871__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004872{
Christopher Fauleta2097962019-07-15 16:25:33 +02004873 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004874}
4875
Christopher Fauleta2097962019-07-15 16:25:33 +02004876/*
4877 *
4878 *
4879 * Class HTTP
4880 *
4881 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004882 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004883
4884/* Returns a struct hlua_txn if the stack entry "ud" is
4885 * a class stream, otherwise it throws an error.
4886 */
4887__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004888{
Christopher Fauleta2097962019-07-15 16:25:33 +02004889 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
4890}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004891
Christopher Fauleta2097962019-07-15 16:25:33 +02004892/* This function creates and push in the stack a HTTP object
4893 * according with a current TXN.
4894 */
4895static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
4896{
4897 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004898
Christopher Fauleta2097962019-07-15 16:25:33 +02004899 /* Check stack size. */
4900 if (!lua_checkstack(L, 3))
4901 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004902
Christopher Fauleta2097962019-07-15 16:25:33 +02004903 /* Create the object: obj[0] = userdata.
4904 * Note that the base of the Converters object is the
4905 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004906 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004907 lua_newtable(L);
4908 htxn = lua_newuserdata(L, sizeof(*htxn));
4909 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004910
4911 htxn->s = txn->s;
4912 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02004913 htxn->dir = txn->dir;
4914 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004915
4916 /* Pop a class stream metatable and affect it to the table. */
4917 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
4918 lua_setmetatable(L, -2);
4919
4920 return 1;
4921}
4922
4923/* This function creates ans returns an array of HTTP headers.
4924 * This function does not fails. It is used as wrapper with the
4925 * 2 following functions.
4926 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004927__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004928{
Christopher Fauleta2097962019-07-15 16:25:33 +02004929 struct htx *htx;
4930 int32_t pos;
4931
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004932 /* Create the table. */
4933 lua_newtable(L);
4934
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004935
Christopher Fauleta2097962019-07-15 16:25:33 +02004936 htx = htxbuf(&msg->chn->buf);
4937 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4938 struct htx_blk *blk = htx_get_blk(htx, pos);
4939 enum htx_blk_type type = htx_get_blk_type(blk);
4940 struct ist n, v;
4941 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01004942
Christopher Fauleta2097962019-07-15 16:25:33 +02004943 if (type == HTX_BLK_HDR) {
4944 n = htx_get_blk_name(htx,blk);
4945 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01004946 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004947 else if (type == HTX_BLK_EOH)
4948 break;
4949 else
4950 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01004951
Christopher Fauleta2097962019-07-15 16:25:33 +02004952 /* Check for existing entry:
4953 * assume that the table is on the top of the stack, and
4954 * push the key in the stack, the function lua_gettable()
4955 * perform the lookup.
4956 */
4957 lua_pushlstring(L, n.ptr, n.len);
4958 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01004959
Christopher Fauleta2097962019-07-15 16:25:33 +02004960 switch (lua_type(L, -1)) {
4961 case LUA_TNIL:
4962 /* Table not found, create it. */
4963 lua_pop(L, 1); /* remove the nil value. */
4964 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
4965 lua_newtable(L); /* create and push empty table. */
4966 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
4967 lua_rawseti(L, -2, 0); /* index header value (pop it). */
4968 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01004969 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01004970
Christopher Fauleta2097962019-07-15 16:25:33 +02004971 case LUA_TTABLE:
4972 /* Entry found: push the value in the table. */
4973 len = lua_rawlen(L, -1);
4974 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
4975 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
4976 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
4977 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004978
Christopher Fauleta2097962019-07-15 16:25:33 +02004979 default:
4980 /* Other cases are errors. */
4981 hlua_pusherror(L, "internal error during the parsing of headers.");
4982 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004983 }
4984 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004985 return 1;
4986}
4987
4988__LJMP static int hlua_http_req_get_headers(lua_State *L)
4989{
4990 struct hlua_txn *htxn;
4991
4992 MAY_LJMP(check_args(L, 1, "req_get_headers"));
4993 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4994
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004995 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02004996 WILL_LJMP(lua_error(L));
4997
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004998 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004999}
5000
5001__LJMP static int hlua_http_res_get_headers(lua_State *L)
5002{
5003 struct hlua_txn *htxn;
5004
5005 MAY_LJMP(check_args(L, 1, "res_get_headers"));
5006 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5007
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005008 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005009 WILL_LJMP(lua_error(L));
5010
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005011 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005012}
5013
5014/* This function replace full header, or just a value in
5015 * the request or in the response. It is a wrapper fir the
5016 * 4 following functions.
5017 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005018__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005019{
5020 size_t name_len;
5021 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5022 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
5023 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02005024 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02005025 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005026
Dragan Dosen26743032019-04-30 15:54:36 +02005027 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005028 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
5029
Christopher Fauleta2097962019-07-15 16:25:33 +02005030 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005031 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02005032 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005033 return 0;
5034}
5035
5036__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
5037{
5038 struct hlua_txn *htxn;
5039
5040 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5041 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5042
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005043 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005044 WILL_LJMP(lua_error(L));
5045
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005046 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005047}
5048
5049__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
5050{
5051 struct hlua_txn *htxn;
5052
5053 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
5054 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5055
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005056 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005057 WILL_LJMP(lua_error(L));
5058
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005059 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005060}
5061
5062__LJMP static int hlua_http_req_rep_val(lua_State *L)
5063{
5064 struct hlua_txn *htxn;
5065
5066 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5067 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5068
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005069 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005070 WILL_LJMP(lua_error(L));
5071
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005072 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005073}
5074
5075__LJMP static int hlua_http_res_rep_val(lua_State *L)
5076{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005077 struct hlua_txn *htxn;
5078
5079 MAY_LJMP(check_args(L, 4, "res_rep_val"));
5080 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5081
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005082 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005083 WILL_LJMP(lua_error(L));
5084
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005085 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005086}
5087
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005088/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005089 * It is a wrapper for the 2 following functions.
5090 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005091__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005092{
5093 size_t len;
5094 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005095 struct htx *htx = htxbuf(&msg->chn->buf);
5096 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005097
Christopher Fauleta2097962019-07-15 16:25:33 +02005098 ctx.blk = NULL;
5099 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5100 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005101 return 0;
5102}
5103
5104__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5105{
5106 struct hlua_txn *htxn;
5107
5108 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5109 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5110
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005111 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005112 WILL_LJMP(lua_error(L));
5113
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005114 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005115}
5116
5117__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5118{
5119 struct hlua_txn *htxn;
5120
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005121 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005122 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5123
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005124 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005125 WILL_LJMP(lua_error(L));
5126
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005127 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005128}
5129
5130/* This function adds an header. It is a wrapper used by
5131 * the 2 following functions.
5132 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005133__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005134{
5135 size_t name_len;
5136 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5137 size_t value_len;
5138 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005139 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005140
Christopher Fauleta2097962019-07-15 16:25:33 +02005141 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5142 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005143 return 0;
5144}
5145
5146__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5147{
5148 struct hlua_txn *htxn;
5149
5150 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5151 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5152
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005153 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005154 WILL_LJMP(lua_error(L));
5155
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005156 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005157}
5158
5159__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5160{
5161 struct hlua_txn *htxn;
5162
5163 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5164 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5165
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005166 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005167 WILL_LJMP(lua_error(L));
5168
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005169 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005170}
5171
5172static int hlua_http_req_set_hdr(lua_State *L)
5173{
5174 struct hlua_txn *htxn;
5175
5176 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5177 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5178
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005179 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005180 WILL_LJMP(lua_error(L));
5181
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005182 hlua_http_del_hdr(L, &htxn->s->txn->req);
5183 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005184}
5185
5186static int hlua_http_res_set_hdr(lua_State *L)
5187{
5188 struct hlua_txn *htxn;
5189
5190 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
5191 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5192
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005193 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005194 WILL_LJMP(lua_error(L));
5195
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005196 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
5197 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005198}
5199
5200/* This function set the method. */
5201static int hlua_http_req_set_meth(lua_State *L)
5202{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005203 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005204 size_t name_len;
5205 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005206
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005207 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005208 WILL_LJMP(lua_error(L));
5209
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005210 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005211 return 1;
5212}
5213
5214/* This function set the method. */
5215static int hlua_http_req_set_path(lua_State *L)
5216{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005217 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005218 size_t name_len;
5219 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02005220
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005221 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005222 WILL_LJMP(lua_error(L));
5223
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005224 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005225 return 1;
5226}
5227
5228/* This function set the query-string. */
5229static int hlua_http_req_set_query(lua_State *L)
5230{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005231 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005232 size_t name_len;
5233 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005234
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005235 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005236 WILL_LJMP(lua_error(L));
5237
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005238 /* Check length. */
5239 if (name_len > trash.size - 1) {
5240 lua_pushboolean(L, 0);
5241 return 1;
5242 }
5243
5244 /* Add the mark question as prefix. */
5245 chunk_reset(&trash);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005246 trash.area[trash.data++] = '?';
5247 memcpy(trash.area + trash.data, name, name_len);
5248 trash.data += name_len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005249
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005250 lua_pushboolean(L,
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005251 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005252 return 1;
5253}
5254
5255/* This function set the uri. */
5256static int hlua_http_req_set_uri(lua_State *L)
5257{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005258 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005259 size_t name_len;
5260 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005261
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005262 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005263 WILL_LJMP(lua_error(L));
5264
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005265 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005266 return 1;
5267}
5268
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005269/* This function set the response code & optionally reason. */
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005270static int hlua_http_res_set_status(lua_State *L)
5271{
5272 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5273 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Faulet96bff762019-12-17 13:46:18 +01005274 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
5275 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005276
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005277 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005278 WILL_LJMP(lua_error(L));
5279
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005280 http_res_set_status(code, reason, htxn->s);
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005281 return 0;
5282}
5283
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005284/*
5285 *
5286 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005287 * Class TXN
5288 *
5289 *
5290 */
5291
5292/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02005293 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005294 */
5295__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
5296{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02005297 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005298}
5299
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005300__LJMP static int hlua_set_var(lua_State *L)
5301{
5302 struct hlua_txn *htxn;
5303 const char *name;
5304 size_t len;
5305 struct sample smp;
5306
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005307 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
5308 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005309
5310 /* It is useles to retrieve the stream, but this function
5311 * runs only in a stream context.
5312 */
5313 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5314 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5315
5316 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01005317 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005318 hlua_lua2smp(L, 3, &smp);
5319
5320 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01005321 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005322
5323 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
5324 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
5325 else
5326 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
5327
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005328 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005329}
5330
Christopher Faulet85d79c92016-11-09 16:54:56 +01005331__LJMP static int hlua_unset_var(lua_State *L)
5332{
5333 struct hlua_txn *htxn;
5334 const char *name;
5335 size_t len;
5336 struct sample smp;
5337
5338 MAY_LJMP(check_args(L, 2, "unset_var"));
5339
5340 /* It is useles to retrieve the stream, but this function
5341 * runs only in a stream context.
5342 */
5343 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5344 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5345
5346 /* Unset the variable. */
5347 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005348 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
5349 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01005350}
5351
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005352__LJMP static int hlua_get_var(lua_State *L)
5353{
5354 struct hlua_txn *htxn;
5355 const char *name;
5356 size_t len;
5357 struct sample smp;
5358
5359 MAY_LJMP(check_args(L, 2, "get_var"));
5360
5361 /* It is useles to retrieve the stream, but this function
5362 * runs only in a stream context.
5363 */
5364 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5365 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5366
Willy Tarreau7560dd42016-03-10 16:28:58 +01005367 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreau6204cd92016-03-10 16:33:04 +01005368 if (!vars_get_by_name(name, len, &smp)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005369 lua_pushnil(L);
5370 return 1;
5371 }
5372
5373 return hlua_smp2lua(L, &smp);
5374}
5375
Willy Tarreau59551662015-03-10 14:23:13 +01005376__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005377{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005378 struct hlua *hlua;
5379
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005380 MAY_LJMP(check_args(L, 2, "set_priv"));
5381
Willy Tarreau87b09662015-04-03 00:22:06 +02005382 /* It is useles to retrieve the stream, but this function
5383 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005384 */
5385 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005386
5387 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005388 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005389 if (!hlua)
5390 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005391
5392 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005393 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005394
5395 /* Get and store new value. */
5396 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5397 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5398
5399 return 0;
5400}
5401
Willy Tarreau59551662015-03-10 14:23:13 +01005402__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005403{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005404 struct hlua *hlua;
5405
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005406 MAY_LJMP(check_args(L, 1, "get_priv"));
5407
Willy Tarreau87b09662015-04-03 00:22:06 +02005408 /* It is useles to retrieve the stream, but this function
5409 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005410 */
5411 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005412
5413 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005414 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005415 if (!hlua) {
5416 lua_pushnil(L);
5417 return 1;
5418 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005419
5420 /* Push configuration index in the stack. */
5421 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5422
5423 return 1;
5424}
5425
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005426/* Create stack entry containing a class TXN. This function
5427 * return 0 if the stack does not contains free slots,
5428 * otherwise it returns 1.
5429 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005430static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005431{
Willy Tarreaude491382015-04-06 11:04:28 +02005432 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005433
5434 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005435 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005436 return 0;
5437
5438 /* NOTE: The allocation never fails. The failure
5439 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005440 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005441 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005442 /* Create the object: obj[0] = userdata. */
5443 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02005444 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005445 lua_rawseti(L, -2, 0);
5446
Willy Tarreaude491382015-04-06 11:04:28 +02005447 htxn->s = s;
5448 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01005449 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005450 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005451
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005452 /* Create the "f" field that contains a list of fetches. */
5453 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005454 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005455 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005456 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005457
5458 /* Create the "sf" field that contains a list of stringsafe fetches. */
5459 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005460 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005461 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005462 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005463
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005464 /* Create the "c" field that contains a list of converters. */
5465 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02005466 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005467 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005468 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005469
5470 /* Create the "sc" field that contains a list of stringsafe converters. */
5471 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01005472 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005473 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005474 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005475
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005476 /* Create the "req" field that contains the request channel object. */
5477 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005478 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005479 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005480 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005481
5482 /* Create the "res" field that contains the response channel object. */
5483 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005484 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005485 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005486 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005487
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005488 /* Creates the HTTP object is the current proxy allows http. */
5489 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01005490 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02005491 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005492 return 0;
5493 }
5494 else
5495 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005496 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005497
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005498 /* Pop a class sesison metatable and affect it to the userdata. */
5499 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
5500 lua_setmetatable(L, -2);
5501
5502 return 1;
5503}
5504
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005505__LJMP static int hlua_txn_deflog(lua_State *L)
5506{
5507 const char *msg;
5508 struct hlua_txn *htxn;
5509
5510 MAY_LJMP(check_args(L, 2, "deflog"));
5511 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5512 msg = MAY_LJMP(luaL_checkstring(L, 2));
5513
5514 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
5515 return 0;
5516}
5517
5518__LJMP static int hlua_txn_log(lua_State *L)
5519{
5520 int level;
5521 const char *msg;
5522 struct hlua_txn *htxn;
5523
5524 MAY_LJMP(check_args(L, 3, "log"));
5525 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5526 level = MAY_LJMP(luaL_checkinteger(L, 2));
5527 msg = MAY_LJMP(luaL_checkstring(L, 3));
5528
5529 if (level < 0 || level >= NB_LOG_LEVELS)
5530 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
5531
5532 hlua_sendlog(htxn->s->be, level, msg);
5533 return 0;
5534}
5535
5536__LJMP static int hlua_txn_log_debug(lua_State *L)
5537{
5538 const char *msg;
5539 struct hlua_txn *htxn;
5540
5541 MAY_LJMP(check_args(L, 2, "Debug"));
5542 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5543 msg = MAY_LJMP(luaL_checkstring(L, 2));
5544 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
5545 return 0;
5546}
5547
5548__LJMP static int hlua_txn_log_info(lua_State *L)
5549{
5550 const char *msg;
5551 struct hlua_txn *htxn;
5552
5553 MAY_LJMP(check_args(L, 2, "Info"));
5554 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5555 msg = MAY_LJMP(luaL_checkstring(L, 2));
5556 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
5557 return 0;
5558}
5559
5560__LJMP static int hlua_txn_log_warning(lua_State *L)
5561{
5562 const char *msg;
5563 struct hlua_txn *htxn;
5564
5565 MAY_LJMP(check_args(L, 2, "Warning"));
5566 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5567 msg = MAY_LJMP(luaL_checkstring(L, 2));
5568 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
5569 return 0;
5570}
5571
5572__LJMP static int hlua_txn_log_alert(lua_State *L)
5573{
5574 const char *msg;
5575 struct hlua_txn *htxn;
5576
5577 MAY_LJMP(check_args(L, 2, "Alert"));
5578 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5579 msg = MAY_LJMP(luaL_checkstring(L, 2));
5580 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
5581 return 0;
5582}
5583
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005584__LJMP static int hlua_txn_set_loglevel(lua_State *L)
5585{
5586 struct hlua_txn *htxn;
5587 int ll;
5588
5589 MAY_LJMP(check_args(L, 2, "set_loglevel"));
5590 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5591 ll = MAY_LJMP(luaL_checkinteger(L, 2));
5592
5593 if (ll < 0 || ll > 7)
5594 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
5595
5596 htxn->s->logs.level = ll;
5597 return 0;
5598}
5599
5600__LJMP static int hlua_txn_set_tos(lua_State *L)
5601{
5602 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005603 int tos;
5604
5605 MAY_LJMP(check_args(L, 2, "set_tos"));
5606 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5607 tos = MAY_LJMP(luaL_checkinteger(L, 2));
5608
Willy Tarreau1a18b542018-12-11 16:37:42 +01005609 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005610 return 0;
5611}
5612
5613__LJMP static int hlua_txn_set_mark(lua_State *L)
5614{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005615 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005616 int mark;
5617
5618 MAY_LJMP(check_args(L, 2, "set_mark"));
5619 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5620 mark = MAY_LJMP(luaL_checkinteger(L, 2));
5621
Lukas Tribus579e3e32019-08-11 18:03:45 +02005622 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005623 return 0;
5624}
5625
Patrick Hemmer268a7072018-05-11 12:52:31 -04005626__LJMP static int hlua_txn_set_priority_class(lua_State *L)
5627{
5628 struct hlua_txn *htxn;
5629
5630 MAY_LJMP(check_args(L, 2, "set_priority_class"));
5631 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5632 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
5633 return 0;
5634}
5635
5636__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
5637{
5638 struct hlua_txn *htxn;
5639
5640 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
5641 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5642 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
5643 return 0;
5644}
5645
Christopher Faulet700d9e82020-01-31 12:21:52 +01005646/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005647 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01005648 * message and terminate the transaction. It returns 1 on success and 0 on
5649 * error. The Reply must be on top of the stack.
5650 */
5651__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
5652{
5653 struct htx *htx;
5654 struct htx_sl *sl;
5655 struct h1m h1m;
5656 const char *status, *reason, *body;
5657 size_t status_len, reason_len, body_len;
5658 int ret, code, flags;
5659
5660 code = 200;
5661 status = "200";
5662 status_len = 3;
5663 ret = lua_getfield(L, -1, "status");
5664 if (ret == LUA_TNUMBER) {
5665 code = lua_tointeger(L, -1);
5666 status = lua_tolstring(L, -1, &status_len);
5667 }
5668 lua_pop(L, 1);
5669
5670 reason = http_get_reason(code);
5671 reason_len = strlen(reason);
5672 ret = lua_getfield(L, -1, "reason");
5673 if (ret == LUA_TSTRING)
5674 reason = lua_tolstring(L, -1, &reason_len);
5675 lua_pop(L, 1);
5676
5677 body = NULL;
5678 body_len = 0;
5679 ret = lua_getfield(L, -1, "body");
5680 if (ret == LUA_TSTRING)
5681 body = lua_tolstring(L, -1, &body_len);
5682 lua_pop(L, 1);
5683
5684 /* Prepare the response before inserting the headers */
5685 h1m_init_res(&h1m);
5686 htx = htx_from_buf(&s->res.buf);
5687 channel_htx_truncate(&s->res, htx);
5688 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
5689 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5690 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
5691 ist2(status, status_len), ist2(reason, reason_len));
5692 }
5693 else {
5694 flags = HTX_SL_F_IS_RESP;
5695 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
5696 ist2(status, status_len), ist2(reason, reason_len));
5697 }
5698 if (!sl)
5699 goto fail;
5700 sl->info.res.status = code;
5701
5702 /* Push in the stack the "headers" entry. */
5703 ret = lua_getfield(L, -1, "headers");
5704 if (ret != LUA_TTABLE)
5705 goto skip_headers;
5706
5707 lua_pushnil(L);
5708 while (lua_next(L, -2) != 0) {
5709 struct ist name, value;
5710 const char *n, *v;
5711 size_t nlen, vlen;
5712
5713 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
5714 /* Skip element if the key is not a string or if the value is not a table */
5715 goto next_hdr;
5716 }
5717
5718 n = lua_tolstring(L, -2, &nlen);
5719 name = ist2(n, nlen);
5720 if (isteqi(name, ist("content-length"))) {
5721 /* Always skip content-length header. It will be added
5722 * later with the correct len
5723 */
5724 goto next_hdr;
5725 }
5726
5727 /* Loop on header's values */
5728 lua_pushnil(L);
5729 while (lua_next(L, -2)) {
5730 if (!lua_isstring(L, -1)) {
5731 /* Skip the value if it is not a string */
5732 goto next_value;
5733 }
5734
5735 v = lua_tolstring(L, -1, &vlen);
5736 value = ist2(v, vlen);
5737
5738 if (isteqi(name, ist("transfer-encoding")))
5739 h1_parse_xfer_enc_header(&h1m, value);
5740 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
5741 goto fail;
5742
5743 next_value:
5744 lua_pop(L, 1);
5745 }
5746
5747 next_hdr:
5748 lua_pop(L, 1);
5749 }
5750 skip_headers:
5751 lua_pop(L, 1);
5752
5753 /* Update h1m flags: CLEN is set if CHNK is not present */
5754 if (!(h1m.flags & H1_MF_CHNK)) {
5755 const char *clen = ultoa(body_len);
5756
5757 h1m.flags |= H1_MF_CLEN;
5758 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
5759 goto fail;
5760 }
5761 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5762 h1m.flags |= H1_MF_XFER_LEN;
5763
5764 /* Update HTX start-line flags */
5765 if (h1m.flags & H1_MF_XFER_ENC)
5766 flags |= HTX_SL_F_XFER_ENC;
5767 if (h1m.flags & H1_MF_XFER_LEN) {
5768 flags |= HTX_SL_F_XFER_LEN;
5769 if (h1m.flags & H1_MF_CHNK)
5770 flags |= HTX_SL_F_CHNK;
5771 else if (h1m.flags & H1_MF_CLEN)
5772 flags |= HTX_SL_F_CLEN;
5773 if (h1m.body_len == 0)
5774 flags |= HTX_SL_F_BODYLESS;
5775 }
5776 sl->flags |= flags;
5777
5778
5779 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005780 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01005781 goto fail;
5782
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005783 htx->flags |= HTX_FL_EOM;
5784
Christopher Faulet700d9e82020-01-31 12:21:52 +01005785 /* Now, forward the response and terminate the transaction */
5786 s->txn->status = code;
5787 htx_to_buf(htx, &s->res.buf);
5788 if (!http_forward_proxy_resp(s, 1))
5789 goto fail;
5790
5791 return 1;
5792
5793 fail:
5794 channel_htx_truncate(&s->res, htx);
5795 return 0;
5796}
5797
5798/* Terminate a transaction if called from a lua action. For TCP streams,
5799 * processing is just aborted. Nothing is returned to the client and all
5800 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
5801 * is forwarded to the client before terminating the transaction. On success,
5802 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
5803 * with ACT_RET_ERR code. If this function is not called from a lua action, it
5804 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005805 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005806__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005807{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02005808 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01005809 struct stream *s;
5810 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005811
Willy Tarreaub2ccb562015-04-06 11:11:15 +02005812 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005813
Christopher Faulet700d9e82020-01-31 12:21:52 +01005814 /* If the flags NOTERM is set, we cannot terminate the session, so we
5815 * just end the execution of the current lua code. */
5816 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005817 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005818
Christopher Faulet700d9e82020-01-31 12:21:52 +01005819 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005820 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01005821 struct channel *req = &s->req;
5822 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01005823
Christopher Faulet700d9e82020-01-31 12:21:52 +01005824 channel_auto_read(req);
5825 channel_abort(req);
5826 channel_auto_close(req);
5827 channel_erase(req);
5828
5829 res->wex = tick_add_ifset(now_ms, res->wto);
5830 channel_auto_read(res);
5831 channel_auto_close(res);
5832 channel_shutr_now(res);
5833
5834 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
5835 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005836 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02005837
Christopher Faulet700d9e82020-01-31 12:21:52 +01005838 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
5839 /* No reply or invalid reply */
5840 s->txn->status = 0;
5841 http_reply_and_close(s, 0, NULL);
5842 }
5843 else {
5844 /* Remove extra args to have the reply on top of the stack */
5845 if (lua_gettop(L) > 2)
5846 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005847
Christopher Faulet700d9e82020-01-31 12:21:52 +01005848 if (!hlua_txn_forward_reply(L, s)) {
5849 if (!(s->flags & SF_ERR_MASK))
5850 s->flags |= SF_ERR_PRXCOND;
5851 lua_pushinteger(L, ACT_RET_ERR);
5852 WILL_LJMP(hlua_done(L));
5853 return 0; /* Never reached */
5854 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02005855 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005856
Christopher Faulet700d9e82020-01-31 12:21:52 +01005857 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
5858 if (htxn->dir == SMP_OPT_DIR_REQ) {
5859 /* let's log the request time */
5860 s->logs.tv_request = now;
5861 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02005862 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01005863 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005864
Christopher Faulet700d9e82020-01-31 12:21:52 +01005865 done:
5866 if (!(s->flags & SF_ERR_MASK))
5867 s->flags |= SF_ERR_LOCAL;
5868 if (!(s->flags & SF_FINST_MASK))
5869 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005870
Christopher Faulet4ad73102020-03-05 11:07:31 +01005871 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005872 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005873 return 0;
5874}
5875
Christopher Faulet700d9e82020-01-31 12:21:52 +01005876/*
5877 *
5878 *
5879 * Class REPLY
5880 *
5881 *
5882 */
5883
5884/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
5885 * free slots, the function fails and returns 0;
5886 */
5887static int hlua_txn_reply_new(lua_State *L)
5888{
5889 struct hlua_txn *htxn;
5890 const char *reason, *body = NULL;
5891 int ret, status;
5892
5893 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005894 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01005895 hlua_pusherror(L, "txn object is not an HTTP transaction.");
5896 WILL_LJMP(lua_error(L));
5897 }
5898
5899 /* Default value */
5900 status = 200;
5901 reason = http_get_reason(status);
5902
5903 if (lua_istable(L, 2)) {
5904 /* load status and reason from the table argument at index 2 */
5905 ret = lua_getfield(L, 2, "status");
5906 if (ret == LUA_TNIL)
5907 goto reason;
5908 else if (ret != LUA_TNUMBER) {
5909 /* invalid status: ignore the reason */
5910 goto body;
5911 }
5912 status = lua_tointeger(L, -1);
5913
5914 reason:
5915 lua_pop(L, 1); /* restore the stack: remove status */
5916 ret = lua_getfield(L, 2, "reason");
5917 if (ret == LUA_TSTRING)
5918 reason = lua_tostring(L, -1);
5919
5920 body:
5921 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
5922 ret = lua_getfield(L, 2, "body");
5923 if (ret == LUA_TSTRING)
5924 body = lua_tostring(L, -1);
5925 lua_pop(L, 1); /* restore the stack: remove body */
5926 }
5927
5928 /* Create the Reply table */
5929 lua_newtable(L);
5930
5931 /* Add status element */
5932 lua_pushstring(L, "status");
5933 lua_pushinteger(L, status);
5934 lua_settable(L, -3);
5935
5936 /* Add reason element */
5937 reason = http_get_reason(status);
5938 lua_pushstring(L, "reason");
5939 lua_pushstring(L, reason);
5940 lua_settable(L, -3);
5941
5942 /* Add body element, nil if undefined */
5943 lua_pushstring(L, "body");
5944 if (body)
5945 lua_pushstring(L, body);
5946 else
5947 lua_pushnil(L);
5948 lua_settable(L, -3);
5949
5950 /* Add headers element */
5951 lua_pushstring(L, "headers");
5952 lua_newtable(L);
5953
5954 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
5955 if (lua_istable(L, 2)) {
5956 /* load headers from the table argument at index 2. If it is a table, copy it. */
5957 ret = lua_getfield(L, 2, "headers");
5958 if (ret == LUA_TTABLE) {
5959 /* stack: [ ... <headers:table>, <table> ] */
5960 lua_pushnil(L);
5961 while (lua_next(L, -2) != 0) {
5962 /* stack: [ ... <headers:table>, <table>, k, v] */
5963 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
5964 /* invalid value type, skip it */
5965 lua_pop(L, 1);
5966 continue;
5967 }
5968
5969
5970 /* Duplicate the key and swap it with the value. */
5971 lua_pushvalue(L, -2);
5972 lua_insert(L, -2);
5973 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
5974
5975 lua_newtable(L);
5976 lua_insert(L, -2);
5977 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
5978
5979 if (lua_isstring(L, -1)) {
5980 /* push the value in the inner table */
5981 lua_rawseti(L, -2, 1);
5982 }
5983 else { /* table */
5984 lua_pushnil(L);
5985 while (lua_next(L, -2) != 0) {
5986 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
5987 if (!lua_isstring(L, -1)) {
5988 /* invalid value type, skip it*/
5989 lua_pop(L, 1);
5990 continue;
5991 }
5992 /* push the value in the inner table */
5993 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
5994 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
5995 }
5996 lua_pop(L, 1);
5997 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
5998 }
5999
6000 /* push (k,v) on the stack in the headers table:
6001 * stack: [ ... <headers:table>, <table>, k, k, v ]
6002 */
6003 lua_settable(L, -5);
6004 /* stack: [ ... <headers:table>, <table>, k ] */
6005 }
6006 }
6007 lua_pop(L, 1);
6008 }
6009 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
6010 lua_settable(L, -3);
6011 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
6012
6013 /* Pop a class sesison metatable and affect it to the userdata. */
6014 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
6015 lua_setmetatable(L, -2);
6016 return 1;
6017}
6018
6019/* Set the reply status code, and optionally the reason. If no reason is
6020 * provided, the default one corresponding to the status code is used.
6021 */
6022__LJMP static int hlua_txn_reply_set_status(lua_State *L)
6023{
6024 int status = MAY_LJMP(luaL_checkinteger(L, 2));
6025 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6026
6027 /* First argument (self) must be a table */
6028 luaL_checktype(L, 1, LUA_TTABLE);
6029
6030 if (status < 100 || status > 599) {
6031 lua_pushboolean(L, 0);
6032 return 1;
6033 }
6034 if (!reason)
6035 reason = http_get_reason(status);
6036
6037 lua_pushinteger(L, status);
6038 lua_setfield(L, 1, "status");
6039
6040 lua_pushstring(L, reason);
6041 lua_setfield(L, 1, "reason");
6042
6043 lua_pushboolean(L, 1);
6044 return 1;
6045}
6046
6047/* Add a header into the reply object. Each header name is associated to an
6048 * array of values in the "headers" table. If the header name is not found, a
6049 * new entry is created.
6050 */
6051__LJMP static int hlua_txn_reply_add_header(lua_State *L)
6052{
6053 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6054 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
6055 int ret;
6056
6057 /* First argument (self) must be a table */
6058 luaL_checktype(L, 1, LUA_TTABLE);
6059
6060 /* Push in the stack the "headers" entry. */
6061 ret = lua_getfield(L, 1, "headers");
6062 if (ret != LUA_TTABLE) {
6063 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
6064 WILL_LJMP(lua_error(L));
6065 }
6066
6067 /* check if the header is already registered. If not, register it. */
6068 ret = lua_getfield(L, -1, name);
6069 if (ret == LUA_TNIL) {
6070 /* Entry not found. */
6071 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
6072
6073 /* Insert the new header name in the array in the top of the stack.
6074 * It left the new array in the top of the stack.
6075 */
6076 lua_newtable(L);
6077 lua_pushstring(L, name);
6078 lua_pushvalue(L, -2);
6079 lua_settable(L, -4);
6080 }
6081 else if (ret != LUA_TTABLE) {
6082 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
6083 WILL_LJMP(lua_error(L));
6084 }
6085
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07006086 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01006087 * the header value as new entry.
6088 */
6089 lua_pushstring(L, value);
6090 ret = lua_rawlen(L, -2);
6091 lua_rawseti(L, -2, ret + 1);
6092
6093 lua_pushboolean(L, 1);
6094 return 1;
6095}
6096
6097/* Remove all occurrences of a given header name. */
6098__LJMP static int hlua_txn_reply_del_header(lua_State *L)
6099{
6100 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6101 int ret;
6102
6103 /* First argument (self) must be a table */
6104 luaL_checktype(L, 1, LUA_TTABLE);
6105
6106 /* Push in the stack the "headers" entry. */
6107 ret = lua_getfield(L, 1, "headers");
6108 if (ret != LUA_TTABLE) {
6109 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
6110 WILL_LJMP(lua_error(L));
6111 }
6112
6113 lua_pushstring(L, name);
6114 lua_pushnil(L);
6115 lua_settable(L, -3);
6116
6117 lua_pushboolean(L, 1);
6118 return 1;
6119}
6120
6121/* Set the reply's body. Overwrite any existing entry. */
6122__LJMP static int hlua_txn_reply_set_body(lua_State *L)
6123{
6124 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
6125
6126 /* First argument (self) must be a table */
6127 luaL_checktype(L, 1, LUA_TTABLE);
6128
6129 lua_pushstring(L, payload);
6130 lua_setfield(L, 1, "body");
6131
6132 lua_pushboolean(L, 1);
6133 return 1;
6134}
6135
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01006136__LJMP static int hlua_log(lua_State *L)
6137{
6138 int level;
6139 const char *msg;
6140
6141 MAY_LJMP(check_args(L, 2, "log"));
6142 level = MAY_LJMP(luaL_checkinteger(L, 1));
6143 msg = MAY_LJMP(luaL_checkstring(L, 2));
6144
6145 if (level < 0 || level >= NB_LOG_LEVELS)
6146 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
6147
6148 hlua_sendlog(NULL, level, msg);
6149 return 0;
6150}
6151
6152__LJMP static int hlua_log_debug(lua_State *L)
6153{
6154 const char *msg;
6155
6156 MAY_LJMP(check_args(L, 1, "debug"));
6157 msg = MAY_LJMP(luaL_checkstring(L, 1));
6158 hlua_sendlog(NULL, LOG_DEBUG, msg);
6159 return 0;
6160}
6161
6162__LJMP static int hlua_log_info(lua_State *L)
6163{
6164 const char *msg;
6165
6166 MAY_LJMP(check_args(L, 1, "info"));
6167 msg = MAY_LJMP(luaL_checkstring(L, 1));
6168 hlua_sendlog(NULL, LOG_INFO, msg);
6169 return 0;
6170}
6171
6172__LJMP static int hlua_log_warning(lua_State *L)
6173{
6174 const char *msg;
6175
6176 MAY_LJMP(check_args(L, 1, "warning"));
6177 msg = MAY_LJMP(luaL_checkstring(L, 1));
6178 hlua_sendlog(NULL, LOG_WARNING, msg);
6179 return 0;
6180}
6181
6182__LJMP static int hlua_log_alert(lua_State *L)
6183{
6184 const char *msg;
6185
6186 MAY_LJMP(check_args(L, 1, "alert"));
6187 msg = MAY_LJMP(luaL_checkstring(L, 1));
6188 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006189 return 0;
6190}
6191
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006192__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006193{
6194 int wakeup_ms = lua_tointeger(L, -1);
6195 if (now_ms < wakeup_ms)
Willy Tarreau9635e032018-10-16 17:52:55 +02006196 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006197 return 0;
6198}
6199
6200__LJMP static int hlua_sleep(lua_State *L)
6201{
6202 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006203 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006204
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006205 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006206
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006207 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006208 wakeup_ms = tick_add(now_ms, delay);
6209 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006210
Willy Tarreau9635e032018-10-16 17:52:55 +02006211 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006212 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006213}
6214
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006215__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006216{
6217 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006218 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006219
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006220 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006221
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006222 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006223 wakeup_ms = tick_add(now_ms, delay);
6224 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006225
Willy Tarreau9635e032018-10-16 17:52:55 +02006226 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006227 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006228}
6229
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006230/* This functionis an LUA binding. it permits to give back
6231 * the hand at the HAProxy scheduler. It is used when the
6232 * LUA processing consumes a lot of time.
6233 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006234__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006235{
6236 return 0;
6237}
6238
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006239__LJMP static int hlua_yield(lua_State *L)
6240{
Willy Tarreau9635e032018-10-16 17:52:55 +02006241 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006242 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006243}
6244
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006245/* This function change the nice of the currently executed
6246 * task. It is used set low or high priority at the current
6247 * task.
6248 */
Willy Tarreau59551662015-03-10 14:23:13 +01006249__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006250{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006251 struct hlua *hlua;
6252 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006253
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006254 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006255 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006256
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006257 /* Get hlua struct, or NULL if we execute from main lua state */
6258 hlua = hlua_gethlua(L);
6259
6260 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006261 if (!hlua || !hlua->task)
6262 return 0;
6263
6264 if (nice < -1024)
6265 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006266 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006267 nice = 1024;
6268
6269 hlua->task->nice = nice;
6270 return 0;
6271}
6272
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006273/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006274 * HAProxy task subsystem when the task is awaked. The LUA runtime can
6275 * return an E_AGAIN signal, the emmiter of this signal must set a
6276 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006277 *
6278 * Task wrapper are longjmp safe because the only one Lua code
6279 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006280 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01006281struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006282{
Olivier Houchard9f6af332018-05-25 14:04:04 +02006283 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006284 enum hlua_exec status;
6285
Christopher Faulet5bc99722018-04-25 10:34:45 +02006286 if (task->thread_mask == MAX_THREADS_MASK)
6287 task_set_affinity(task, tid_bit);
6288
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006289 /* If it is the first call to the task, we must initialize the
6290 * execution timeouts.
6291 */
6292 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02006293 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006294
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006295 /* Execute the Lua code. */
6296 status = hlua_ctx_resume(hlua, 1);
6297
6298 switch (status) {
6299 /* finished or yield */
6300 case HLUA_E_OK:
6301 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006302 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02006303 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006304 break;
6305
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01006306 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01006307 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02006308 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006309 break;
6310
6311 /* finished with error. */
6312 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006313 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006314 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006315 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006316 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006317 break;
6318
6319 case HLUA_E_ERR:
6320 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006321 SEND_ERR(NULL, "Lua task: unknown error.\n");
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006322 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006323 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006324 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006325 break;
6326 }
Emeric Brun253e53e2017-10-17 18:58:40 +02006327 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006328}
6329
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006330/* This function is an LUA binding that register LUA function to be
6331 * executed after the HAProxy configuration parsing and before the
6332 * HAProxy scheduler starts. This function expect only one LUA
6333 * argument that is a function. This function returns nothing, but
6334 * throws if an error is encountered.
6335 */
6336__LJMP static int hlua_register_init(lua_State *L)
6337{
6338 struct hlua_init_function *init;
6339 int ref;
6340
6341 MAY_LJMP(check_args(L, 1, "register_init"));
6342
6343 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6344
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006345 init = calloc(1, sizeof(*init));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006346 if (!init)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006347 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006348
6349 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02006350 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006351 return 0;
6352}
6353
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006354/* This functio is an LUA binding. It permits to register a task
6355 * executed in parallel of the main HAroxy activity. The task is
6356 * created and it is set in the HAProxy scheduler. It can be called
6357 * from the "init" section, "post init" or during the runtime.
6358 *
6359 * Lua prototype:
6360 *
6361 * <none> core.register_task(<function>)
6362 */
6363static int hlua_register_task(lua_State *L)
6364{
Christopher Faulet5294ec02021-04-12 12:24:47 +02006365 struct hlua *hlua = NULL;
6366 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006367 int ref;
Thierry Fournier021d9862020-11-28 23:42:03 +01006368 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006369
6370 MAY_LJMP(check_args(L, 1, "register_task"));
6371
6372 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6373
Thierry Fournier75fc0292020-11-28 13:18:56 +01006374 /* Get the reference state. If the reference is NULL, L is the master
6375 * state, otherwise hlua->T is.
6376 */
6377 hlua = hlua_gethlua(L);
6378 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01006379 /* we are in runtime processing */
6380 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01006381 else
Thierry Fournier021d9862020-11-28 23:42:03 +01006382 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01006383 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01006384
Willy Tarreaubafbe012017-11-24 17:34:44 +01006385 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006386 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02006387 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006388 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006389
Thierry Fournier59f11be2020-11-29 00:37:41 +01006390 /* We are in the common lua state, execute the task anywhere,
6391 * otherwise, inherit the current thread identifier
6392 */
6393 if (state_id == 0)
6394 task = task_new(MAX_THREADS_MASK);
6395 else
6396 task = task_new(tid_bit);
Willy Tarreaue09101e2018-10-16 17:37:12 +02006397 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02006398 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02006399
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006400 task->context = hlua;
6401 task->process = hlua_process_task;
6402
Thierry Fournier021d9862020-11-28 23:42:03 +01006403 if (!hlua_ctx_init(hlua, state_id, task, 1))
Christopher Faulet5294ec02021-04-12 12:24:47 +02006404 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006405
6406 /* Restore the function in the stack. */
6407 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref);
6408 hlua->nargs = 0;
6409
6410 /* Schedule task. */
6411 task_schedule(task, now_ms);
6412
6413 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02006414
6415 alloc_error:
6416 task_destroy(task);
6417 hlua_ctx_destroy(hlua);
6418 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6419 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006420}
6421
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006422/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
6423 * doesn't allow "yield" functions because the HAProxy engine cannot
6424 * resume converters.
6425 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006426static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006427{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006428 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006429 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006430 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006431
Willy Tarreaube508f12016-03-10 11:47:01 +01006432 if (!stream)
6433 return 0;
6434
Willy Tarreau87b09662015-04-03 00:22:06 +02006435 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006436 * Lua context can be not initialized. This behavior
6437 * permits to save performances because a systematic
6438 * Lua initialization cause 5% performances loss.
6439 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006440 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006441 struct hlua *hlua;
6442
6443 hlua = pool_alloc(pool_head_hlua);
6444 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006445 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6446 return 0;
6447 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006448 HLUA_INIT(hlua);
6449 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006450 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006451 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6452 return 0;
6453 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006454 }
6455
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006456 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006457 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006458
6459 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006460 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006461 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6462 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006463 else
6464 error = "critical error";
6465 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006466 return 0;
6467 }
6468
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006469 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006470 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006471 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006472 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006473 return 0;
6474 }
6475
6476 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006477 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006478
6479 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006480 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006481 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006482 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006483 return 0;
6484 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006485 hlua_smp2lua(stream->hlua->T, smp);
6486 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006487
6488 /* push keywords in the stack. */
6489 if (arg_p) {
6490 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006491 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006492 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006493 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006494 return 0;
6495 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006496 hlua_arg2lua(stream->hlua->T, arg_p);
6497 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006498 }
6499 }
6500
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006501 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006502 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006503
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006504 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006505 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006506 }
6507
6508 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006509 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006510 /* finished. */
6511 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006512 /* If the stack is empty, the function fails. */
6513 if (lua_gettop(stream->hlua->T) <= 0)
6514 return 0;
6515
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006516 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006517 hlua_lua2smp(stream->hlua->T, -1, smp);
6518 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006519 return 1;
6520
6521 /* yield. */
6522 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006523 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006524 return 0;
6525
6526 /* finished with error. */
6527 case HLUA_E_ERRMSG:
6528 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006529 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006530 fcn->name, lua_tostring(stream->hlua->T, -1));
6531 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006532 return 0;
6533
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006534 case HLUA_E_ETMOUT:
6535 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
6536 return 0;
6537
6538 case HLUA_E_NOMEM:
6539 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
6540 return 0;
6541
6542 case HLUA_E_YIELD:
6543 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
6544 return 0;
6545
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006546 case HLUA_E_ERR:
6547 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006548 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006549 /* fall through */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006550
6551 default:
6552 return 0;
6553 }
6554}
6555
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006556/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
6557 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01006558 * resume sample-fetches. This function will be called by the sample
6559 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006560 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02006561static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
6562 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006563{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006564 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006565 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006566 const char *error;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006567 unsigned int hflags = HLUA_TXN_NOTERM;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006568
Willy Tarreaube508f12016-03-10 11:47:01 +01006569 if (!stream)
6570 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01006571
Willy Tarreau87b09662015-04-03 00:22:06 +02006572 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006573 * Lua context can be not initialized. This behavior
6574 * permits to save performances because a systematic
6575 * Lua initialization cause 5% performances loss.
6576 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006577 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006578 struct hlua *hlua;
6579
6580 hlua = pool_alloc(pool_head_hlua);
6581 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006582 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6583 return 0;
6584 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006585 hlua->T = NULL;
6586 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006587 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006588 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6589 return 0;
6590 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006591 }
6592
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006593 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006594 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006595
6596 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006597 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006598 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6599 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006600 else
6601 error = "critical error";
6602 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006603 return 0;
6604 }
6605
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006606 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006607 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006608 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006609 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006610 return 0;
6611 }
6612
6613 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006614 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006615
6616 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006617 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006618 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006619 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006620 return 0;
6621 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006622 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006623
6624 /* push keywords in the stack. */
6625 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
6626 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006627 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006628 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006629 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006630 return 0;
6631 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006632 hlua_arg2lua(stream->hlua->T, arg_p);
6633 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006634 }
6635
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006636 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006637 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006638
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006639 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006640 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006641 }
6642
6643 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006644 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006645 /* finished. */
6646 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006647 /* If the stack is empty, the function fails. */
6648 if (lua_gettop(stream->hlua->T) <= 0)
6649 return 0;
6650
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006651 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006652 hlua_lua2smp(stream->hlua->T, -1, smp);
6653 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006654
6655 /* Set the end of execution flag. */
6656 smp->flags &= ~SMP_F_MAY_CHANGE;
6657 return 1;
6658
6659 /* yield. */
6660 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006661 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006662 return 0;
6663
6664 /* finished with error. */
6665 case HLUA_E_ERRMSG:
6666 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006667 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006668 fcn->name, lua_tostring(stream->hlua->T, -1));
6669 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006670 return 0;
6671
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006672 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006673 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
6674 return 0;
6675
6676 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006677 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
6678 return 0;
6679
6680 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006681 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
6682 return 0;
6683
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006684 case HLUA_E_ERR:
6685 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006686 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006687 /* fall through */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006688
6689 default:
6690 return 0;
6691 }
6692}
6693
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006694/* This function is an LUA binding used for registering
6695 * "sample-conv" functions. It expects a converter name used
6696 * in the haproxy configuration file, and an LUA function.
6697 */
6698__LJMP static int hlua_register_converters(lua_State *L)
6699{
6700 struct sample_conv_kw_list *sck;
6701 const char *name;
6702 int ref;
6703 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02006704 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006705 struct sample_conv *sc;
6706 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006707
6708 MAY_LJMP(check_args(L, 2, "register_converters"));
6709
6710 /* First argument : converter name. */
6711 name = MAY_LJMP(luaL_checkstring(L, 1));
6712
6713 /* Second argument : lua function. */
6714 ref = MAY_LJMP(hlua_checkfunction(L, 2));
6715
Thierry Fournierf67442e2020-11-28 20:41:07 +01006716 /* Check if the converter is already registered */
6717 trash = get_trash_chunk();
6718 chunk_printf(trash, "lua.%s", name);
6719 sc = find_sample_conv(trash->area, trash->data);
6720 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01006721 fcn = sc->private;
6722 if (fcn->function_ref[hlua_state_id] != -1) {
6723 ha_warning("Trying to register converter 'lua.%s' more than once. "
6724 "This will become a hard error in version 2.5.\n", name);
6725 }
6726 fcn->function_ref[hlua_state_id] = ref;
6727 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006728 }
6729
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006730 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006731 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006732 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +02006733 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01006734 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006735 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +02006736 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006737
6738 /* Fill fcn. */
6739 fcn->name = strdup(name);
6740 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +02006741 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01006742 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006743
6744 /* List head */
6745 sck->list.n = sck->list.p = NULL;
6746
6747 /* converter keyword. */
6748 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006749 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006750 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +02006751 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006752
6753 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
6754 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01006755 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 +01006756 sck->kw[0].val_args = NULL;
6757 sck->kw[0].in_type = SMP_T_STR;
6758 sck->kw[0].out_type = SMP_T_STR;
6759 sck->kw[0].private = fcn;
6760
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006761 /* Register this new converter */
6762 sample_register_convs(sck);
6763
6764 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +02006765
6766 alloc_error:
6767 release_hlua_function(fcn);
6768 ha_free(&sck);
6769 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6770 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006771}
6772
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006773/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006774 * "sample-fetch" functions. It expects a converter name used
6775 * in the haproxy configuration file, and an LUA function.
6776 */
6777__LJMP static int hlua_register_fetches(lua_State *L)
6778{
6779 const char *name;
6780 int ref;
6781 int len;
6782 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +02006783 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006784 struct sample_fetch *sf;
6785 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006786
6787 MAY_LJMP(check_args(L, 2, "register_fetches"));
6788
6789 /* First argument : sample-fetch name. */
6790 name = MAY_LJMP(luaL_checkstring(L, 1));
6791
6792 /* Second argument : lua function. */
6793 ref = MAY_LJMP(hlua_checkfunction(L, 2));
6794
Thierry Fournierf67442e2020-11-28 20:41:07 +01006795 /* Check if the sample-fetch is already registered */
6796 trash = get_trash_chunk();
6797 chunk_printf(trash, "lua.%s", name);
6798 sf = find_sample_fetch(trash->area, trash->data);
6799 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01006800 fcn = sf->private;
6801 if (fcn->function_ref[hlua_state_id] != -1) {
6802 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
6803 "This will become a hard error in version 2.5.\n", name);
6804 }
6805 fcn->function_ref[hlua_state_id] = ref;
6806 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006807 }
6808
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006809 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006810 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006811 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +02006812 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01006813 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006814 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +02006815 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006816
6817 /* Fill fcn. */
6818 fcn->name = strdup(name);
6819 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +02006820 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01006821 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006822
6823 /* List head */
6824 sfk->list.n = sfk->list.p = NULL;
6825
6826 /* sample-fetch keyword. */
6827 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006828 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006829 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +02006830 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006831
6832 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
6833 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01006834 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 +01006835 sfk->kw[0].val_args = NULL;
6836 sfk->kw[0].out_type = SMP_T_STR;
6837 sfk->kw[0].use = SMP_USE_HTTP_ANY;
6838 sfk->kw[0].val = 0;
6839 sfk->kw[0].private = fcn;
6840
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006841 /* Register this new fetch. */
6842 sample_register_fetches(sfk);
6843
6844 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +02006845
6846 alloc_error:
6847 release_hlua_function(fcn);
6848 ha_free(&sfk);
6849 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6850 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006851}
6852
Christopher Faulet501465d2020-02-26 14:54:16 +01006853/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006854 */
Christopher Faulet501465d2020-02-26 14:54:16 +01006855__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006856{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006857 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006858 unsigned int delay;
6859 unsigned int wakeup_ms;
6860
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006861 /* Get hlua struct, or NULL if we execute from main lua state */
6862 hlua = hlua_gethlua(L);
6863 if (!hlua) {
6864 return 0;
6865 }
6866
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006867 MAY_LJMP(check_args(L, 1, "wake_time"));
6868
6869 delay = MAY_LJMP(luaL_checkinteger(L, 1));
6870 wakeup_ms = tick_add(now_ms, delay);
6871 hlua->wake_time = wakeup_ms;
6872 return 0;
6873}
6874
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006875/* This function is a wrapper to execute each LUA function declared as an action
6876 * wrapper during the initialisation period. This function may return any
6877 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
6878 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
6879 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006880 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006881static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02006882 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006883{
6884 char **arg;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006885 unsigned int hflags = 0;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006886 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006887 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006888
6889 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006890 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
6891 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
6892 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
6893 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006894 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006895 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006896 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006897 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006898
Willy Tarreau87b09662015-04-03 00:22:06 +02006899 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006900 * Lua context can be not initialized. This behavior
6901 * permits to save performances because a systematic
6902 * Lua initialization cause 5% performances loss.
6903 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006904 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006905 struct hlua *hlua;
6906
6907 hlua = pool_alloc(pool_head_hlua);
6908 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006909 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006910 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006911 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006912 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006913 HLUA_INIT(hlua);
6914 s->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006915 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 +01006916 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006917 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006918 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006919 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006920 }
6921
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006922 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006923 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006924
6925 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006926 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006927 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
6928 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006929 else
6930 error = "critical error";
6931 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006932 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006933 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006934 }
6935
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006936 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006937 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006938 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006939 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006940 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006941 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006942 }
6943
6944 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006945 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 +01006946
Willy Tarreau87b09662015-04-03 00:22:06 +02006947 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006948 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006949 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006950 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006951 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006952 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006953 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006954 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006955
6956 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006957 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006958 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006959 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006960 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006961 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006962 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006963 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006964 lua_pushstring(s->hlua->T, *arg);
6965 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006966 }
6967
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006968 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006969 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006970
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006971 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006972 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006973 }
6974
6975 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01006976 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006977 /* finished. */
6978 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006979 /* Catch the return value */
6980 if (lua_gettop(s->hlua->T) > 0)
6981 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006982
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006983 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02006984 if (act_ret == ACT_RET_YIELD) {
6985 if (flags & ACT_OPT_FINAL)
6986 goto err_yield;
6987
Christopher Faulet8f587ea2020-07-28 12:01:55 +02006988 if (dir == SMP_OPT_DIR_REQ)
6989 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
6990 s->hlua->wake_time);
6991 else
6992 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
6993 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006994 }
6995 goto end;
6996
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006997 /* yield. */
6998 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01006999 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007000 if (dir == SMP_OPT_DIR_REQ)
7001 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
7002 s->hlua->wake_time);
7003 else
7004 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
7005 s->hlua->wake_time);
7006
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007007 /* Some actions can be wake up when a "write" event
7008 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007009 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007010 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02007011 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01007012 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007013 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01007014 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007015 act_ret = ACT_RET_YIELD;
7016 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007017
7018 /* finished with error. */
7019 case HLUA_E_ERRMSG:
7020 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007021 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007022 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007023 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007024 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007025
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007026 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +01007027 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007028 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007029
7030 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +01007031 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007032 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007033
7034 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02007035 err_yield:
7036 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007037 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007038 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007039 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007040
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007041 case HLUA_E_ERR:
7042 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007043 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007044 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007045
7046 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007047 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007048 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007049
7050 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02007051 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007052 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007053 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007054}
7055
Willy Tarreau144f84a2021-03-02 16:09:26 +01007056struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007057{
Olivier Houchard9f6af332018-05-25 14:04:04 +02007058 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007059
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007060 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02007061 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02007062 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007063}
7064
7065static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7066{
7067 struct stream_interface *si = ctx->owner;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007068 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007069 struct task *task;
7070 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007071 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007072
Willy Tarreaubafbe012017-11-24 17:34:44 +01007073 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007074 if (!hlua) {
7075 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007076 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007077 return 0;
7078 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007079 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007080 ctx->ctx.hlua_apptcp.hlua = hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007081 ctx->ctx.hlua_apptcp.flags = 0;
7082
7083 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007084 task = task_new(tid_bit);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007085 if (!task) {
7086 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007087 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007088 return 0;
7089 }
7090 task->nice = 0;
7091 task->context = ctx;
7092 task->process = hlua_applet_wakeup;
7093 ctx->ctx.hlua_apptcp.task = task;
7094
7095 /* In the execution wrappers linked with a stream, the
7096 * Lua context can be not initialized. This behavior
7097 * permits to save performances because a systematic
7098 * Lua initialization cause 5% performances loss.
7099 */
Thierry Fournierc7492592020-11-28 23:57:24 +01007100 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 +02007101 SEND_ERR(px, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007102 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007103 return 0;
7104 }
7105
7106 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007107 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007108
7109 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007110 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007111 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7112 error = lua_tostring(hlua->T, -1);
7113 else
7114 error = "critical error";
7115 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007116 ctx->rule->arg.hlua_rule->fcn->name, error);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007117 return 0;
7118 }
7119
7120 /* Check stack available size. */
7121 if (!lua_checkstack(hlua->T, 1)) {
7122 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007123 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007124 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007125 return 0;
7126 }
7127
7128 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007129 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007130
7131 /* Create and and push object stream in the stack. */
7132 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
7133 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007134 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007135 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007136 return 0;
7137 }
7138 hlua->nargs = 1;
7139
7140 /* push keywords in the stack. */
7141 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7142 if (!lua_checkstack(hlua->T, 1)) {
7143 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007144 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007145 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007146 return 0;
7147 }
7148 lua_pushstring(hlua->T, *arg);
7149 hlua->nargs++;
7150 }
7151
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007152 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007153
7154 /* Wakeup the applet ASAP. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007155 si_cant_get(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01007156 si_rx_endp_more(si);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007157
7158 return 1;
7159}
7160
Willy Tarreau60409db2019-08-21 14:14:50 +02007161void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007162{
7163 struct stream_interface *si = ctx->owner;
7164 struct stream *strm = si_strm(si);
7165 struct channel *res = si_ic(si);
7166 struct act_rule *rule = ctx->rule;
7167 struct proxy *px = strm->be;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007168 struct hlua *hlua = ctx->ctx.hlua_apptcp.hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007169
7170 /* The applet execution is already done. */
Olivier Houchard594c8c52018-08-28 14:41:31 +02007171 if (ctx->ctx.hlua_apptcp.flags & APPLET_DONE) {
7172 /* eat the whole request */
7173 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007174 return;
Olivier Houchard594c8c52018-08-28 14:41:31 +02007175 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007176
7177 /* If the stream is disconnect or closed, ldo nothing. */
7178 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7179 return;
7180
7181 /* Execute the function. */
7182 switch (hlua_ctx_resume(hlua, 1)) {
7183 /* finished. */
7184 case HLUA_E_OK:
7185 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7186
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007187 /* eat the whole request */
Willy Tarreaua79021a2018-06-15 18:07:57 +02007188 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007189 res->flags |= CF_READ_NULL;
7190 si_shutr(si);
7191 return;
7192
7193 /* yield. */
7194 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01007195 if (hlua->wake_time != TICK_ETERNITY)
7196 task_schedule(ctx->ctx.hlua_apptcp.task, hlua->wake_time);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007197 return;
7198
7199 /* finished with error. */
7200 case HLUA_E_ERRMSG:
7201 /* Display log. */
7202 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007203 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007204 lua_pop(hlua->T, 1);
7205 goto error;
7206
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007207 case HLUA_E_ETMOUT:
7208 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007209 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007210 goto error;
7211
7212 case HLUA_E_NOMEM:
7213 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007214 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007215 goto error;
7216
7217 case HLUA_E_YIELD: /* unexpected */
7218 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007219 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007220 goto error;
7221
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007222 case HLUA_E_ERR:
7223 /* Display log. */
7224 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007225 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007226 goto error;
7227
7228 default:
7229 goto error;
7230 }
7231
7232error:
7233
7234 /* For all other cases, just close the stream. */
7235 si_shutw(si);
7236 si_shutr(si);
7237 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7238}
7239
7240static void hlua_applet_tcp_release(struct appctx *ctx)
7241{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007242 task_destroy(ctx->ctx.hlua_apptcp.task);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007243 ctx->ctx.hlua_apptcp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007244 hlua_ctx_destroy(ctx->ctx.hlua_apptcp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007245 ctx->ctx.hlua_apptcp.hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007246}
7247
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007248/* The function returns 1 if the initialisation is complete, 0 if
7249 * an errors occurs and -1 if more data are required for initializing
7250 * the applet.
7251 */
7252static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7253{
7254 struct stream_interface *si = ctx->owner;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007255 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007256 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007257 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007258 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007259 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007260
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007261 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01007262 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007263 if (!hlua) {
7264 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007265 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007266 return 0;
7267 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007268 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007269 ctx->ctx.hlua_apphttp.hlua = hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007270 ctx->ctx.hlua_apphttp.left_bytes = -1;
7271 ctx->ctx.hlua_apphttp.flags = 0;
7272
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01007273 if (txn->req.flags & HTTP_MSGF_VER_11)
7274 ctx->ctx.hlua_apphttp.flags |= APPLET_HTTP11;
7275
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007276 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007277 task = task_new(tid_bit);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007278 if (!task) {
7279 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007280 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007281 return 0;
7282 }
7283 task->nice = 0;
7284 task->context = ctx;
7285 task->process = hlua_applet_wakeup;
7286 ctx->ctx.hlua_apphttp.task = task;
7287
7288 /* In the execution wrappers linked with a stream, the
7289 * Lua context can be not initialized. This behavior
7290 * permits to save performances because a systematic
7291 * Lua initialization cause 5% performances loss.
7292 */
Thierry Fournierc7492592020-11-28 23:57:24 +01007293 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 +02007294 SEND_ERR(px, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007295 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007296 return 0;
7297 }
7298
7299 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007300 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007301
7302 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007303 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007304 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7305 error = lua_tostring(hlua->T, -1);
7306 else
7307 error = "critical error";
7308 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007309 ctx->rule->arg.hlua_rule->fcn->name, error);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007310 return 0;
7311 }
7312
7313 /* Check stack available size. */
7314 if (!lua_checkstack(hlua->T, 1)) {
7315 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007316 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007317 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007318 return 0;
7319 }
7320
7321 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007322 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007323
7324 /* Create and and push object stream in the stack. */
7325 if (!hlua_applet_http_new(hlua->T, ctx)) {
7326 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007327 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007328 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007329 return 0;
7330 }
7331 hlua->nargs = 1;
7332
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007333 /* push keywords in the stack. */
7334 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7335 if (!lua_checkstack(hlua->T, 1)) {
7336 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007337 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007338 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007339 return 0;
7340 }
7341 lua_pushstring(hlua->T, *arg);
7342 hlua->nargs++;
7343 }
7344
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007345 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007346
7347 /* Wakeup the applet when data is ready for read. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007348 si_cant_get(si);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007349
7350 return 1;
7351}
7352
Willy Tarreau60409db2019-08-21 14:14:50 +02007353void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007354{
7355 struct stream_interface *si = ctx->owner;
7356 struct stream *strm = si_strm(si);
7357 struct channel *req = si_oc(si);
7358 struct channel *res = si_ic(si);
7359 struct act_rule *rule = ctx->rule;
7360 struct proxy *px = strm->be;
7361 struct hlua *hlua = ctx->ctx.hlua_apphttp.hlua;
7362 struct htx *req_htx, *res_htx;
7363
7364 res_htx = htx_from_buf(&res->buf);
7365
7366 /* If the stream is disconnect or closed, ldo nothing. */
7367 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7368 goto out;
7369
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007370 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007371 if (!b_size(&res->buf)) {
7372 si_rx_room_blk(si);
7373 goto out;
7374 }
7375 /* check that the output is not closed */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007376 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007377 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7378
7379 /* Set the currently running flag. */
7380 if (!HLUA_IS_RUNNING(hlua) &&
7381 !(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +02007382 if (!co_data(req)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007383 si_cant_get(si);
7384 goto out;
7385 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007386 }
7387
7388 /* Executes The applet if it is not done. */
7389 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
7390
7391 /* Execute the function. */
7392 switch (hlua_ctx_resume(hlua, 1)) {
7393 /* finished. */
7394 case HLUA_E_OK:
7395 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7396 break;
7397
7398 /* yield. */
7399 case HLUA_E_AGAIN:
7400 if (hlua->wake_time != TICK_ETERNITY)
7401 task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007402 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007403
7404 /* finished with error. */
7405 case HLUA_E_ERRMSG:
7406 /* Display log. */
7407 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007408 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007409 lua_pop(hlua->T, 1);
7410 goto error;
7411
7412 case HLUA_E_ETMOUT:
7413 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007414 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007415 goto error;
7416
7417 case HLUA_E_NOMEM:
7418 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007419 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007420 goto error;
7421
7422 case HLUA_E_YIELD: /* unexpected */
7423 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007424 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007425 goto error;
7426
7427 case HLUA_E_ERR:
7428 /* Display log. */
7429 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007430 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007431 goto error;
7432
7433 default:
7434 goto error;
7435 }
7436 }
7437
7438 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007439 if (ctx->ctx.hlua_apphttp.flags & APPLET_RSP_SENT)
7440 goto done;
7441
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007442 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT))
7443 goto error;
7444
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01007445 /* no more data are expected. Don't add TLR because mux-h1 will take care of it */
7446 res_htx->flags |= HTX_FL_EOM;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007447 strm->txn->status = ctx->ctx.hlua_apphttp.status;
7448 ctx->ctx.hlua_apphttp.flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007449 }
7450
7451 done:
7452 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007453 if (!(res->flags & CF_SHUTR)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007454 res->flags |= CF_READ_NULL;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007455 si_shutr(si);
7456 }
7457
7458 /* eat the whole request */
7459 if (co_data(req)) {
7460 req_htx = htx_from_buf(&req->buf);
7461 co_htx_skip(req, req_htx, co_data(req));
7462 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007463 }
7464 }
7465
7466 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007467 htx_to_buf(res_htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007468 return;
7469
7470 error:
7471
7472 /* If we are in HTTP mode, and we are not send any
7473 * data, return a 500 server error in best effort:
7474 * if there is no room available in the buffer,
7475 * just close the connection.
7476 */
7477 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02007478 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007479
7480 channel_erase(res);
7481 res->buf.data = b_data(err);
7482 memcpy(res->buf.area, b_head(err), b_data(err));
7483 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01007484 channel_add_input(res, res_htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007485 }
7486 if (!(strm->flags & SF_ERR_MASK))
7487 strm->flags |= SF_ERR_RESOURCE;
7488 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7489 goto done;
7490}
7491
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007492static void hlua_applet_http_release(struct appctx *ctx)
7493{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007494 task_destroy(ctx->ctx.hlua_apphttp.task);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007495 ctx->ctx.hlua_apphttp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007496 hlua_ctx_destroy(ctx->ctx.hlua_apphttp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007497 ctx->ctx.hlua_apphttp.hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007498}
7499
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007500/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007501 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007502 *
7503 * This function can fail with an abort() due to an Lua critical error.
7504 * We are in the configuration parsing process of HAProxy, this abort() is
7505 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007506 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007507static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
7508 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007509{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007510 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007511 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007512
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007513 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007514 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007515 if (!rule->arg.hlua_rule) {
7516 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007517 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007518 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007519
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007520 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02007521 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
7522 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007523 if (!rule->arg.hlua_rule->args) {
7524 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007525 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007526 }
7527
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007528 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007529 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007530
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007531 /* Expect some arguments */
7532 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007533 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007534 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +02007535 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007536 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007537 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007538 if (!rule->arg.hlua_rule->args[i]) {
7539 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007540 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007541 }
7542 (*cur_arg)++;
7543 }
7544 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007545
Thierry FOURNIER42148732015-09-02 17:17:33 +02007546 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007547 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02007548 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +02007549
7550 error:
7551 if (rule->arg.hlua_rule) {
7552 if (rule->arg.hlua_rule->args) {
7553 for (i = 0; i < fcn->nargs; i++)
7554 ha_free(&rule->arg.hlua_rule->args[i]);
7555 ha_free(&rule->arg.hlua_rule->args);
7556 }
7557 ha_free(&rule->arg.hlua_rule);
7558 }
7559 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007560}
7561
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007562static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
7563 struct act_rule *rule, char **err)
7564{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007565 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007566
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007567 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007568 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007569 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007570 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007571 * the call of this analyzer.
7572 */
7573 if (rule->from != ACT_F_HTTP_REQ) {
7574 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
7575 return ACT_RET_PRS_ERR;
7576 }
7577
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007578 /* Memory for the rule. */
7579 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7580 if (!rule->arg.hlua_rule) {
7581 memprintf(err, "out of memory error");
7582 return ACT_RET_PRS_ERR;
7583 }
7584
7585 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007586 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007587
7588 /* TODO: later accept arguments. */
7589 rule->arg.hlua_rule->args = NULL;
7590
7591 /* Add applet pointer in the rule. */
7592 rule->applet.obj_type = OBJ_TYPE_APPLET;
7593 rule->applet.name = fcn->name;
7594 rule->applet.init = hlua_applet_http_init;
7595 rule->applet.fct = hlua_applet_http_fct;
7596 rule->applet.release = hlua_applet_http_release;
7597 rule->applet.timeout = hlua_timeout_applet;
7598
7599 return ACT_RET_PRS_OK;
7600}
7601
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007602/* This function is an LUA binding used for registering
7603 * "sample-conv" functions. It expects a converter name used
7604 * in the haproxy configuration file, and an LUA function.
7605 */
7606__LJMP static int hlua_register_action(lua_State *L)
7607{
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007608 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007609 const char *name;
7610 int ref;
7611 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007612 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007613 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007614 struct buffer *trash;
7615 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007616
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007617 /* Initialise the number of expected arguments at 0. */
7618 nargs = 0;
7619
7620 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7621 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007622
7623 /* First argument : converter name. */
7624 name = MAY_LJMP(luaL_checkstring(L, 1));
7625
7626 /* Second argument : environment. */
7627 if (lua_type(L, 2) != LUA_TTABLE)
7628 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7629
7630 /* Third argument : lua function. */
7631 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7632
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007633 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007634 if (lua_gettop(L) >= 4)
7635 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
7636
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007637 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007638 lua_pushnil(L);
7639 while (lua_next(L, 2) != 0) {
7640 if (lua_type(L, -1) != LUA_TSTRING)
7641 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7642
Thierry Fournierf67442e2020-11-28 20:41:07 +01007643 /* Check if action exists */
7644 trash = get_trash_chunk();
7645 chunk_printf(trash, "lua.%s", name);
7646 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
7647 akw = tcp_req_cont_action(trash->area);
7648 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
7649 akw = tcp_res_cont_action(trash->area);
7650 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
7651 akw = action_http_req_custom(trash->area);
7652 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
7653 akw = action_http_res_custom(trash->area);
7654 } else {
7655 akw = NULL;
7656 }
7657 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01007658 fcn = akw->private;
7659 if (fcn->function_ref[hlua_state_id] != -1) {
7660 ha_warning("Trying to register action 'lua.%s' more than once. "
7661 "This will become a hard error in version 2.5.\n", name);
7662 }
7663 fcn->function_ref[hlua_state_id] = ref;
7664
7665 /* pop the environment string. */
7666 lua_pop(L, 1);
7667 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007668 }
7669
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007670 /* Check required environment. Only accepted "http" or "tcp". */
7671 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007672 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007673 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007674 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01007675 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007676 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007677 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007678
7679 /* Fill fcn. */
7680 fcn->name = strdup(name);
7681 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007682 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01007683 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007684
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07007685 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007686 fcn->nargs = nargs;
7687
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007688 /* List head */
7689 akl->list.n = akl->list.p = NULL;
7690
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007691 /* action keyword. */
7692 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007693 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007694 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007695 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007696
7697 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
7698
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02007699 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007700 akl->kw[0].private = fcn;
7701 akl->kw[0].parse = action_register_lua;
7702
7703 /* select the action registering point. */
7704 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
7705 tcp_req_cont_keywords_register(akl);
7706 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
7707 tcp_res_cont_keywords_register(akl);
7708 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
7709 http_req_keywords_register(akl);
7710 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
7711 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007712 else {
7713 release_hlua_function(fcn);
7714 if (akl)
7715 ha_free((char **)&(akl->kw[0].kw));
7716 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007717 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007718 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
7719 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007720 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007721
7722 /* pop the environment string. */
7723 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007724
7725 /* reset for next loop */
7726 akl = NULL;
7727 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007728 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007729 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007730
7731 alloc_error:
7732 release_hlua_function(fcn);
7733 ha_free(&akl);
7734 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
7735 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007736}
7737
7738static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
7739 struct act_rule *rule, char **err)
7740{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007741 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007742
Christopher Faulet280f85b2019-07-15 15:02:04 +02007743 if (px->mode == PR_MODE_HTTP) {
7744 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +01007745 return ACT_RET_PRS_ERR;
7746 }
7747
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007748 /* Memory for the rule. */
7749 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7750 if (!rule->arg.hlua_rule) {
7751 memprintf(err, "out of memory error");
7752 return ACT_RET_PRS_ERR;
7753 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007754
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007755 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007756 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007757
7758 /* TODO: later accept arguments. */
7759 rule->arg.hlua_rule->args = NULL;
7760
7761 /* Add applet pointer in the rule. */
7762 rule->applet.obj_type = OBJ_TYPE_APPLET;
7763 rule->applet.name = fcn->name;
7764 rule->applet.init = hlua_applet_tcp_init;
7765 rule->applet.fct = hlua_applet_tcp_fct;
7766 rule->applet.release = hlua_applet_tcp_release;
7767 rule->applet.timeout = hlua_timeout_applet;
7768
7769 return 0;
7770}
7771
7772/* This function is an LUA binding used for registering
7773 * "sample-conv" functions. It expects a converter name used
7774 * in the haproxy configuration file, and an LUA function.
7775 */
7776__LJMP static int hlua_register_service(lua_State *L)
7777{
7778 struct action_kw_list *akl;
7779 const char *name;
7780 const char *env;
7781 int ref;
7782 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +02007783 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007784 struct buffer *trash;
7785 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007786
7787 MAY_LJMP(check_args(L, 3, "register_service"));
7788
7789 /* First argument : converter name. */
7790 name = MAY_LJMP(luaL_checkstring(L, 1));
7791
7792 /* Second argument : environment. */
7793 env = MAY_LJMP(luaL_checkstring(L, 2));
7794
7795 /* Third argument : lua function. */
7796 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7797
Thierry Fournierf67442e2020-11-28 20:41:07 +01007798 /* Check for service already registered */
7799 trash = get_trash_chunk();
7800 chunk_printf(trash, "lua.%s", name);
7801 akw = service_find(trash->area);
7802 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01007803 fcn = akw->private;
7804 if (fcn->function_ref[hlua_state_id] != -1) {
7805 ha_warning("Trying to register service 'lua.%s' more than once. "
7806 "This will become a hard error in version 2.5.\n", name);
7807 }
7808 fcn->function_ref[hlua_state_id] = ref;
7809 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007810 }
7811
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007812 /* Allocate and fill the sample fetch keyword struct. */
7813 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
7814 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007815 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01007816 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007817 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007818 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007819
7820 /* Fill fcn. */
7821 len = strlen("<lua.>") + strlen(name) + 1;
7822 fcn->name = calloc(1, len);
7823 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007824 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007825 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +01007826 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007827
7828 /* List head */
7829 akl->list.n = akl->list.p = NULL;
7830
7831 /* converter keyword. */
7832 len = strlen("lua.") + strlen(name) + 1;
7833 akl->kw[0].kw = calloc(1, len);
7834 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007835 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007836
7837 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
7838
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +01007839 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007840 if (strcmp(env, "tcp") == 0)
7841 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007842 else if (strcmp(env, "http") == 0)
7843 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +02007844 else {
7845 release_hlua_function(fcn);
7846 if (akl)
7847 ha_free((char **)&(akl->kw[0].kw));
7848 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007849 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +01007850 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +02007851 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007852
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02007853 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007854 akl->kw[0].private = fcn;
7855
7856 /* End of array. */
7857 memset(&akl->kw[1], 0, sizeof(*akl->kw));
7858
7859 /* Register this new converter */
7860 service_keywords_register(akl);
7861
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007862 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +02007863
7864 alloc_error:
7865 release_hlua_function(fcn);
7866 ha_free(&akl);
7867 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
7868 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007869}
7870
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007871/* This function initialises Lua cli handler. It copies the
7872 * arguments in the Lua stack and create channel IO objects.
7873 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02007874static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007875{
7876 struct hlua *hlua;
7877 struct hlua_function *fcn;
7878 int i;
7879 const char *error;
7880
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007881 fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007882 appctx->ctx.hlua_cli.fcn = private;
7883
Willy Tarreaubafbe012017-11-24 17:34:44 +01007884 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007885 if (!hlua) {
7886 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007887 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007888 }
7889 HLUA_INIT(hlua);
7890 appctx->ctx.hlua_cli.hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007891
7892 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +05007893 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007894 * applet_http. It is absolutely compatible.
7895 */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007896 appctx->ctx.hlua_cli.task = task_new(tid_bit);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007897 if (!appctx->ctx.hlua_cli.task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +01007898 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007899 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007900 }
7901 appctx->ctx.hlua_cli.task->nice = 0;
7902 appctx->ctx.hlua_cli.task->context = appctx;
7903 appctx->ctx.hlua_cli.task->process = hlua_applet_wakeup;
7904
7905 /* Initialises the Lua context */
Thierry Fournierc7492592020-11-28 23:57:24 +01007906 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 +01007907 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007908 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007909 }
7910
7911 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007912 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007913 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7914 error = lua_tostring(hlua->T, -1);
7915 else
7916 error = "critical error";
7917 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
7918 goto error;
7919 }
7920
7921 /* Check stack available size. */
7922 if (!lua_checkstack(hlua->T, 2)) {
7923 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7924 goto error;
7925 }
7926
7927 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007928 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007929
7930 /* Once the arguments parsed, the CLI is like an AppletTCP,
7931 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007932 */
7933 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
7934 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7935 goto error;
7936 }
7937 hlua->nargs = 1;
7938
7939 /* push keywords in the stack. */
7940 for (i = 0; *args[i]; i++) {
7941 /* Check stack available size. */
7942 if (!lua_checkstack(hlua->T, 1)) {
7943 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7944 goto error;
7945 }
7946 lua_pushstring(hlua->T, args[i]);
7947 hlua->nargs++;
7948 }
7949
7950 /* We must initialize the execution timeouts. */
7951 hlua->max_time = hlua_timeout_session;
7952
7953 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007954 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007955
7956 /* It's ok */
7957 return 0;
7958
7959 /* It's not ok. */
7960error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007961 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007962 hlua_ctx_destroy(hlua);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007963 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007964 return 1;
7965}
7966
7967static int hlua_cli_io_handler_fct(struct appctx *appctx)
7968{
7969 struct hlua *hlua;
7970 struct stream_interface *si;
7971 struct hlua_function *fcn;
7972
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007973 hlua = appctx->ctx.hlua_cli.hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007974 si = appctx->owner;
Willy Tarreau8ae4f752016-12-14 15:41:45 +01007975 fcn = appctx->ctx.hlua_cli.fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007976
7977 /* If the stream is disconnect or closed, ldo nothing. */
7978 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7979 return 1;
7980
7981 /* Execute the function. */
7982 switch (hlua_ctx_resume(hlua, 1)) {
7983
7984 /* finished. */
7985 case HLUA_E_OK:
7986 return 1;
7987
7988 /* yield. */
7989 case HLUA_E_AGAIN:
7990 /* We want write. */
7991 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreaudb398432018-11-15 11:08:52 +01007992 si_rx_room_blk(si);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007993 /* Set the timeout. */
7994 if (hlua->wake_time != TICK_ETERNITY)
7995 task_schedule(hlua->task, hlua->wake_time);
7996 return 0;
7997
7998 /* finished with error. */
7999 case HLUA_E_ERRMSG:
8000 /* Display log. */
8001 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
8002 fcn->name, lua_tostring(hlua->T, -1));
8003 lua_pop(hlua->T, 1);
8004 return 1;
8005
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008006 case HLUA_E_ETMOUT:
8007 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
8008 fcn->name);
8009 return 1;
8010
8011 case HLUA_E_NOMEM:
8012 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
8013 fcn->name);
8014 return 1;
8015
8016 case HLUA_E_YIELD: /* unexpected */
8017 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
8018 fcn->name);
8019 return 1;
8020
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008021 case HLUA_E_ERR:
8022 /* Display log. */
8023 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
8024 fcn->name);
8025 return 1;
8026
8027 default:
8028 return 1;
8029 }
8030
8031 return 1;
8032}
8033
8034static void hlua_cli_io_release_fct(struct appctx *appctx)
8035{
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008036 hlua_ctx_destroy(appctx->ctx.hlua_cli.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008037 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008038}
8039
8040/* This function is an LUA binding used for registering
8041 * new keywords in the cli. It expects a list of keywords
8042 * which are the "path". It is limited to 5 keywords. A
8043 * description of the command, a function to be executed
8044 * for the parsing and a function for io handlers.
8045 */
8046__LJMP static int hlua_register_cli(lua_State *L)
8047{
8048 struct cli_kw_list *cli_kws;
8049 const char *message;
8050 int ref_io;
8051 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008052 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008053 int index;
8054 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008055 struct buffer *trash;
8056 const char *kw[5];
8057 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008058 const char *errmsg;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008059
8060 MAY_LJMP(check_args(L, 3, "register_cli"));
8061
8062 /* First argument : an array of maximum 5 keywords. */
8063 if (!lua_istable(L, 1))
8064 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
8065
8066 /* Second argument : string with contextual message. */
8067 message = MAY_LJMP(luaL_checkstring(L, 2));
8068
8069 /* Third and fourth argument : lua function. */
8070 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
8071
Thierry Fournierf67442e2020-11-28 20:41:07 +01008072 /* Check for CLI service already registered */
8073 trash = get_trash_chunk();
8074 index = 0;
8075 lua_pushnil(L);
8076 memset(kw, 0, sizeof(kw));
8077 while (lua_next(L, 1) != 0) {
8078 if (index >= CLI_PREFIX_KW_NB)
8079 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
8080 if (lua_type(L, -1) != LUA_TSTRING)
8081 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
8082 kw[index] = lua_tostring(L, -1);
8083 if (index == 0)
8084 chunk_printf(trash, "%s", kw[index]);
8085 else
8086 chunk_appendf(trash, " %s", kw[index]);
8087 index++;
8088 lua_pop(L, 1);
8089 }
8090 cli_kw = cli_find_kw_exact((char **)kw);
8091 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008092 fcn = cli_kw->private;
8093 if (fcn->function_ref[hlua_state_id] != -1) {
8094 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
8095 "This will become a hard error in version 2.5.\n", trash->area);
8096 }
8097 fcn->function_ref[hlua_state_id] = ref_io;
8098 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008099 }
8100
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008101 /* Allocate and fill the sample fetch keyword struct. */
8102 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008103 if (!cli_kws) {
8104 errmsg = "Lua out of memory error.";
8105 goto error;
8106 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008107 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008108 if (!fcn) {
8109 errmsg = "Lua out of memory error.";
8110 goto error;
8111 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008112
8113 /* Fill path. */
8114 index = 0;
8115 lua_pushnil(L);
8116 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008117 if (index >= 5) {
8118 errmsg = "1st argument must be a table with a maximum of 5 entries";
8119 goto error;
8120 }
8121 if (lua_type(L, -1) != LUA_TSTRING) {
8122 errmsg = "1st argument must be a table filled with strings";
8123 goto error;
8124 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008125 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008126 if (!cli_kws->kw[0].str_kw[index]) {
8127 errmsg = "Lua out of memory error.";
8128 goto error;
8129 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008130 index++;
8131 lua_pop(L, 1);
8132 }
8133
8134 /* Copy help message. */
8135 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008136 if (!cli_kws->kw[0].usage) {
8137 errmsg = "Lua out of memory error.";
8138 goto error;
8139 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008140
8141 /* Fill fcn io handler. */
8142 len = strlen("<lua.cli>") + 1;
8143 for (i = 0; i < index; i++)
8144 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
8145 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008146 if (!fcn->name) {
8147 errmsg = "Lua out of memory error.";
8148 goto error;
8149 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008150 strncat((char *)fcn->name, "<lua.cli", len);
8151 for (i = 0; i < index; i++) {
8152 strncat((char *)fcn->name, ".", len);
8153 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
8154 }
8155 strncat((char *)fcn->name, ">", len);
Thierry Fournierc7492592020-11-28 23:57:24 +01008156 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008157
8158 /* Fill last entries. */
8159 cli_kws->kw[0].private = fcn;
8160 cli_kws->kw[0].parse = hlua_cli_parse_fct;
8161 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
8162 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
8163
8164 /* Register this new converter */
8165 cli_register_kw(cli_kws);
8166
8167 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008168
8169 error:
8170 release_hlua_function(fcn);
8171 if (cli_kws) {
8172 for (i = 0; i < index; i++)
8173 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
8174 ha_free((char **)&(cli_kws->kw[0].usage));
8175 }
8176 ha_free(&cli_kws);
8177 WILL_LJMP(luaL_error(L, errmsg));
8178 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008179}
8180
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008181static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008182 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008183 char **err, unsigned int *timeout)
8184{
8185 const char *error;
8186
8187 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02008188 if (error == PARSE_TIME_OVER) {
8189 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
8190 args[1], args[0]);
8191 return -1;
8192 }
8193 else if (error == PARSE_TIME_UNDER) {
8194 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
8195 args[1], args[0]);
8196 return -1;
8197 }
8198 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008199 memprintf(err, "%s: invalid timeout", args[0]);
8200 return -1;
8201 }
8202 return 0;
8203}
8204
8205static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008206 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008207 char **err)
8208{
8209 return hlua_read_timeout(args, section_type, curpx, defpx,
8210 file, line, err, &hlua_timeout_session);
8211}
8212
8213static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008214 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008215 char **err)
8216{
8217 return hlua_read_timeout(args, section_type, curpx, defpx,
8218 file, line, err, &hlua_timeout_task);
8219}
8220
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008221static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008222 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008223 char **err)
8224{
8225 return hlua_read_timeout(args, section_type, curpx, defpx,
8226 file, line, err, &hlua_timeout_applet);
8227}
8228
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008229static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008230 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008231 char **err)
8232{
8233 char *error;
8234
8235 hlua_nb_instruction = strtoll(args[1], &error, 10);
8236 if (*error != '\0') {
8237 memprintf(err, "%s: invalid number", args[0]);
8238 return -1;
8239 }
8240 return 0;
8241}
8242
Willy Tarreau32f61e22015-03-18 17:54:59 +01008243static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008244 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +01008245 char **err)
8246{
8247 char *error;
8248
8249 if (*(args[1]) == 0) {
8250 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).\n", args[0]);
8251 return -1;
8252 }
8253 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
8254 if (*error != '\0') {
8255 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
8256 return -1;
8257 }
8258 return 0;
8259}
8260
8261
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008262/* This function is called by the main configuration key "lua-load". It loads and
8263 * execute an lua file during the parsing of the HAProxy configuration file. It is
8264 * the main lua entry point.
8265 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008266 * This function runs with the HAProxy keywords API. It returns -1 if an error
8267 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008268 *
8269 * In some error case, LUA set an error message in top of the stack. This function
8270 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008271 *
8272 * This function can fail with an abort() due to an Lua critical error.
8273 * We are in the configuration parsing process of HAProxy, this abort() is
8274 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008275 */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008276static int hlua_load_state(char *filename, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008277{
8278 int error;
8279
8280 /* Just load and compile the file. */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008281 error = luaL_loadfile(L, filename);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008282 if (error) {
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008283 memprintf(err, "error in Lua file '%s': %s", filename, lua_tostring(L, -1));
8284 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008285 return -1;
8286 }
8287
8288 /* If no syntax error where detected, execute the code. */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008289 error = lua_pcall(L, 0, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008290 switch (error) {
8291 case LUA_OK:
8292 break;
8293 case LUA_ERRRUN:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008294 memprintf(err, "Lua runtime error: %s\n", lua_tostring(L, -1));
8295 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008296 return -1;
8297 case LUA_ERRMEM:
Thierry Fournierde6145f2020-11-29 00:55:53 +01008298 memprintf(err, "Lua out of memory error\n");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008299 return -1;
8300 case LUA_ERRERR:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008301 memprintf(err, "Lua message handler error: %s\n", lua_tostring(L, -1));
8302 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008303 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02008304#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008305 case LUA_ERRGCMM:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008306 memprintf(err, "Lua garbage collector error: %s\n", lua_tostring(L, -1));
8307 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008308 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02008309#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008310 default:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008311 memprintf(err, "Lua unknown error: %s\n", lua_tostring(L, -1));
8312 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008313 return -1;
8314 }
8315
8316 return 0;
8317}
8318
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008319static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008320 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008321 char **err)
8322{
8323 if (*(args[1]) == 0) {
8324 memprintf(err, "'%s' expects a file name as parameter.\n", args[0]);
8325 return -1;
8326 }
8327
Thierry Fournier59f11be2020-11-29 00:37:41 +01008328 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +01008329 hlua_state_id = 0;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008330 ha_set_tid(0);
Thierry Fournierafc63e22020-11-28 17:06:51 +01008331 return hlua_load_state(args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008332}
8333
Thierry Fournier59f11be2020-11-29 00:37:41 +01008334static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008335 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +01008336 char **err)
8337{
8338 int len;
8339
8340 if (*(args[1]) == 0) {
8341 memprintf(err, "'%s' expects a file as parameter.\n", args[0]);
8342 return -1;
8343 }
8344
8345 if (per_thread_load == NULL) {
8346 /* allocate the first entry large enough to store the final NULL */
8347 per_thread_load = calloc(1, sizeof(*per_thread_load));
8348 if (per_thread_load == NULL) {
8349 memprintf(err, "out of memory error");
8350 return -1;
8351 }
8352 }
8353
8354 /* count used entries */
8355 for (len = 0; per_thread_load[len] != NULL; len++)
8356 ;
8357
8358 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
8359 if (per_thread_load == NULL) {
8360 memprintf(err, "out of memory error");
8361 return -1;
8362 }
8363
8364 per_thread_load[len] = strdup(args[1]);
8365 per_thread_load[len + 1] = NULL;
8366
8367 if (per_thread_load[len] == NULL) {
8368 memprintf(err, "out of memory error");
8369 return -1;
8370 }
8371
8372 /* loading for thread 1 only */
8373 hlua_state_id = 1;
8374 ha_set_tid(0);
8375 return hlua_load_state(args[1], hlua_states[1], err);
8376}
8377
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008378/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
8379 * in the given <ctx>.
8380 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +01008381static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008382{
Thierry Fournier3fb9e512020-11-28 10:13:12 +01008383 lua_getglobal(L, "package"); /* push package variable */
8384 lua_pushstring(L, path); /* push given path */
8385 lua_pushstring(L, ";"); /* push semicolon */
8386 lua_getfield(L, -3, type); /* push old path */
8387 lua_concat(L, 3); /* concatenate to new path */
8388 lua_setfield(L, -2, type); /* store new path */
8389 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008390
8391 return 0;
8392}
8393
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008394static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008395 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008396 char **err)
8397{
8398 char *path;
8399 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008400 struct prepend_path *p = NULL;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008401
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008402 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008403 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008404 }
8405
8406 if (!(*args[1])) {
8407 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008408 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008409 }
8410 path = args[1];
8411
8412 if (*args[2]) {
8413 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
8414 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008415 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008416 }
8417 type = args[2];
8418 }
8419
Thierry Fournier59f11be2020-11-29 00:37:41 +01008420 p = calloc(1, sizeof(*p));
8421 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01008422 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008423 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008424 }
8425 p->path = strdup(path);
8426 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01008427 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008428 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008429 }
8430 p->type = strdup(type);
8431 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01008432 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008433 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008434 }
Willy Tarreau2b718102021-04-21 07:32:39 +02008435 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +01008436
8437 hlua_prepend_path(hlua_states[0], type, path);
8438 hlua_prepend_path(hlua_states[1], type, path);
8439 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008440
8441err2:
8442 free(p->type);
8443 free(p->path);
8444err:
8445 free(p);
8446 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008447}
8448
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008449/* configuration keywords declaration */
8450static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008451 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008452 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +01008453 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008454 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
8455 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +02008456 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008457 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +01008458 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008459 { 0, NULL, NULL },
8460}};
8461
Willy Tarreau0108d902018-11-25 19:14:37 +01008462INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
8463
Christopher Fauletafd8f102018-11-08 11:34:21 +01008464
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008465/* This function can fail with an abort() due to an Lua critical error.
8466 * We are in the initialisation process of HAProxy, this abort() is
8467 * tolerated.
8468 */
Thierry Fournierb8cef172020-11-28 15:37:17 +01008469int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008470{
8471 struct hlua_init_function *init;
8472 const char *msg;
8473 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008474 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +01008475 const char *kind;
8476 const char *trace;
8477 int return_status = 1;
8478#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
8479 int nres;
8480#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008481
Willy Tarreaucdb53462020-12-02 12:12:00 +01008482 /* disable memory limit checks if limit is not set */
8483 if (!hlua_global_allocator.limit)
8484 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
8485
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05008486 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +01008487 if (setjmp(safe_ljmp_env) != 0) {
8488 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +01008489 if (lua_type(L, -1) == LUA_TSTRING)
8490 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008491 else
8492 error = "critical error";
8493 fprintf(stderr, "Lua post-init: %s.\n", error);
8494 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +01008495 } else {
8496 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008497 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +02008498
Thierry Fournierb8cef172020-11-28 15:37:17 +01008499 hlua_fcn_post_init(L);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008500
Thierry Fournierc7492592020-11-28 23:57:24 +01008501 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Thierry Fournierb8cef172020-11-28 15:37:17 +01008502 lua_rawgeti(L, LUA_REGISTRYINDEX, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +01008503
8504#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +01008505 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +01008506#else
Thierry Fournierb8cef172020-11-28 15:37:17 +01008507 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +01008508#endif
8509 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008510 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +01008511
8512 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +01008513 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +01008514 break;
Thierry Fournier670db242020-11-28 10:49:59 +01008515
8516 case LUA_ERRERR:
8517 kind = "message handler error";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008518 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01008519 case LUA_ERRRUN:
8520 if (!kind)
8521 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +01008522 msg = lua_tostring(L, -1);
8523 lua_settop(L, 0); /* Empty the stack. */
8524 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01008525 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +01008526 if (msg)
8527 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
8528 else
8529 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
8530 return_status = 0;
8531 break;
8532
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008533 default:
Thierry Fournier670db242020-11-28 10:49:59 +01008534 /* Unknown error */
8535 kind = "Unknown error";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008536 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01008537 case LUA_YIELD:
8538 /* yield is not configured at this step, this state doesn't happen */
8539 if (!kind)
8540 kind = "yield not allowed";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008541 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01008542 case LUA_ERRMEM:
8543 if (!kind)
8544 kind = "out of memory error";
Thierry Fournierb8cef172020-11-28 15:37:17 +01008545 lua_settop(L, 0);
8546 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01008547 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +01008548 ha_alert("Lua init: %s: %s\n", kind, trace);
8549 return_status = 0;
8550 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008551 }
Thierry Fournier670db242020-11-28 10:49:59 +01008552 if (!return_status)
8553 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008554 }
Thierry Fournier3c539322020-11-28 16:05:05 +01008555
8556 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +01008557 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008558}
8559
Thierry Fournierb8cef172020-11-28 15:37:17 +01008560int hlua_post_init()
8561{
Thierry Fournier59f11be2020-11-29 00:37:41 +01008562 int ret;
8563 int i;
8564 int errors;
8565 char *err = NULL;
8566 struct hlua_function *fcn;
8567
Thierry Fournierb8cef172020-11-28 15:37:17 +01008568#if USE_OPENSSL
8569 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01008570 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +01008571 int saved_used_backed = global.ssl_used_backend;
8572 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01008573 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +01008574 global.ssl_used_backend = saved_used_backed;
8575 }
8576#endif
8577
Thierry Fournierc7492592020-11-28 23:57:24 +01008578 /* Perform post init of common thread */
8579 hlua_state_id = 0;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008580 ha_set_tid(0);
8581 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
8582 if (ret == 0)
8583 return 0;
8584
8585 /* init remaining lua states and load files */
8586 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
8587
8588 /* set thread context */
8589 ha_set_tid(hlua_state_id - 1);
8590
8591 /* Init lua state */
8592 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
8593
8594 /* Load lua files */
8595 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
8596 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
8597 if (ret != 0) {
8598 ha_alert("Lua init: %s\n", err);
8599 return 0;
8600 }
8601 }
8602 }
8603
8604 /* Reset thread context */
8605 ha_set_tid(0);
8606
8607 /* Execute post init for all states */
8608 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
8609
8610 /* set thread context */
8611 ha_set_tid(hlua_state_id - 1);
8612
8613 /* run post init */
8614 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
8615 if (ret == 0)
8616 return 0;
8617 }
8618
8619 /* Reset thread context */
8620 ha_set_tid(0);
8621
8622 /* control functions registering. Each function must have:
8623 * - only the function_ref[0] set positive and all other to -1
8624 * - only the function_ref[0] set to -1 and all other positive
8625 * This ensure a same reference is not used both in shared
8626 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05008627 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +01008628 * complicated to found for the end user.
8629 */
8630 errors = 0;
8631 list_for_each_entry(fcn, &referenced_functions, l) {
8632 ret = 0;
8633 for (i = 1; i < global.nbthread + 1; i++) {
8634 if (fcn->function_ref[i] == -1)
8635 ret--;
8636 else
8637 ret++;
8638 }
8639 if (abs(ret) != global.nbthread) {
8640 ha_alert("Lua function '%s' is not referenced in all thread. "
8641 "Expect function in all thread or in none thread.\n", fcn->name);
8642 errors++;
8643 continue;
8644 }
8645
8646 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05008647 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
8648 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +01008649 "exclusive.\n", fcn->name);
8650 errors++;
8651 }
8652 }
8653
8654 if (errors > 0)
8655 return 0;
8656
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05008657 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +01008658 * -1 in order to have probably a segfault if someone use it
8659 */
8660 hlua_state_id = -1;
8661
8662 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +01008663}
8664
Willy Tarreau32f61e22015-03-18 17:54:59 +01008665/* The memory allocator used by the Lua stack. <ud> is a pointer to the
8666 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
8667 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +01008668 * allocation. <nsize> is the requested new size. A new allocation is
8669 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +01008670 * zero. This one verifies that the limits are respected but is optimized
8671 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreau32f61e22015-03-18 17:54:59 +01008672 */
8673static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
8674{
8675 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +01008676 size_t limit, old, new;
8677
Tim Duesterhus22586522021-01-08 10:35:33 +01008678 if (unlikely(!ptr && !nsize))
8679 return NULL;
8680
Willy Tarreaucdb53462020-12-02 12:12:00 +01008681 /* a limit of ~0 means unlimited and boot complete, so there's no need
8682 * for accounting anymore.
8683 */
Christopher Fauletcc2c4f82021-03-24 14:52:24 +01008684 if (likely(~zone->limit == 0))
8685 return realloc(ptr, nsize);
Willy Tarreau32f61e22015-03-18 17:54:59 +01008686
Willy Tarreaud36c7fa2020-12-02 12:26:29 +01008687 if (!ptr)
8688 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +01008689
Willy Tarreaucdb53462020-12-02 12:12:00 +01008690 /* enforce strict limits across all threads */
8691 limit = zone->limit;
8692 old = _HA_ATOMIC_LOAD(&zone->allocated);
8693 do {
8694 new = old + nsize - osize;
8695 if (unlikely(nsize && limit && new > limit))
8696 return NULL;
8697 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +01008698
8699 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +01008700
8701 if (unlikely(!ptr && nsize)) // failed
8702 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
8703
8704 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +01008705 return ptr;
8706}
8707
Thierry Fournierecb83c22020-11-28 15:49:44 +01008708/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008709 * We are in the initialisation process of HAProxy, this abort() is
8710 * tolerated.
8711 */
Thierry Fournierecb83c22020-11-28 15:49:44 +01008712lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01008713{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008714 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008715 int idx;
8716 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008717 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008718 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008719 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008720 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008721 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008722 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008723
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008724 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008725 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008726
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008727 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008728 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008729 *context = NULL;
8730
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008731 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008732 * the Lua function can fail with an abort. We are in the initialisation
8733 * process of HAProxy, this abort() is tolerated.
8734 */
8735
Thierry Fournier3c539322020-11-28 16:05:05 +01008736 /* Call post initialisation function in safe environment. */
8737 if (setjmp(safe_ljmp_env) != 0) {
8738 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008739 if (lua_type(L, -1) == LUA_TSTRING)
8740 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +01008741 else
8742 error_msg = "critical error";
8743 fprintf(stderr, "Lua init: %s.\n", error_msg);
8744 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +01008745 } else {
8746 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +01008747 }
8748
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008749 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008750 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008751#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
8752#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
8753#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008754 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008755#endif
8756#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008757 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008758#endif
8759#undef HLUA_PREPEND_PATH_TOSTRING
8760#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008761
Thierry Fournier59f11be2020-11-29 00:37:41 +01008762 /* Apply configured prepend path */
8763 list_for_each_entry(pp, &prepend_path_list, l)
8764 hlua_prepend_path(L, pp->type, pp->path);
8765
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008766 /*
8767 *
8768 * Create "core" object.
8769 *
8770 */
8771
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +01008772 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008773 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008774
Thierry Fournierecb83c22020-11-28 15:49:44 +01008775 /* set the thread id */
8776 hlua_class_const_int(L, "thread", thread_num);
8777
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008778 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008779 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008780 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008781
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008782 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008783 hlua_class_function(L, "register_init", hlua_register_init);
8784 hlua_class_function(L, "register_task", hlua_register_task);
8785 hlua_class_function(L, "register_fetches", hlua_register_fetches);
8786 hlua_class_function(L, "register_converters", hlua_register_converters);
8787 hlua_class_function(L, "register_action", hlua_register_action);
8788 hlua_class_function(L, "register_service", hlua_register_service);
8789 hlua_class_function(L, "register_cli", hlua_register_cli);
8790 hlua_class_function(L, "yield", hlua_yield);
8791 hlua_class_function(L, "set_nice", hlua_set_nice);
8792 hlua_class_function(L, "sleep", hlua_sleep);
8793 hlua_class_function(L, "msleep", hlua_msleep);
8794 hlua_class_function(L, "add_acl", hlua_add_acl);
8795 hlua_class_function(L, "del_acl", hlua_del_acl);
8796 hlua_class_function(L, "set_map", hlua_set_map);
8797 hlua_class_function(L, "del_map", hlua_del_map);
8798 hlua_class_function(L, "tcp", hlua_socket_new);
8799 hlua_class_function(L, "log", hlua_log);
8800 hlua_class_function(L, "Debug", hlua_log_debug);
8801 hlua_class_function(L, "Info", hlua_log_info);
8802 hlua_class_function(L, "Warning", hlua_log_warning);
8803 hlua_class_function(L, "Alert", hlua_log_alert);
8804 hlua_class_function(L, "done", hlua_done);
8805 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008806
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008807 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008808
8809 /*
8810 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008811 * Create "act" object.
8812 *
8813 */
8814
8815 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008816 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008817
8818 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008819 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
8820 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
8821 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
8822 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
8823 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
8824 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
8825 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
8826 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008827
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008828 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01008829
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008830 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008831
8832 /*
8833 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008834 * Register class Map
8835 *
8836 */
8837
8838 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008839 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008840
8841 /* register pattern types. */
8842 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008843 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01008844 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008845 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008846 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01008847 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008848
8849 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008850 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008851
8852 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008853 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008854
Ilya Shipitsind4259502020-04-08 01:07:56 +05008855 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008856 lua_pushstring(L, "__index");
8857 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008858
8859 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008860 hlua_class_function(L, "lookup", hlua_map_lookup);
8861 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008862
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008863 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008864
Thierry Fournier45e78d72016-02-19 18:34:46 +01008865 /* Register previous table in the registry with reference and named entry.
8866 * The function hlua_register_metatable() pops the stack, so we
8867 * previously create a copy of the table.
8868 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008869 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
8870 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008871
8872 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008873 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008874
8875 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008876 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008877
8878 /*
8879 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008880 * Register class Channel
8881 *
8882 */
8883
8884 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008885 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008886
Ilya Shipitsind4259502020-04-08 01:07:56 +05008887 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008888 lua_pushstring(L, "__index");
8889 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008890
8891 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008892 hlua_class_function(L, "get", hlua_channel_get);
8893 hlua_class_function(L, "dup", hlua_channel_dup);
8894 hlua_class_function(L, "getline", hlua_channel_getline);
8895 hlua_class_function(L, "set", hlua_channel_set);
8896 hlua_class_function(L, "append", hlua_channel_append);
8897 hlua_class_function(L, "send", hlua_channel_send);
8898 hlua_class_function(L, "forward", hlua_channel_forward);
8899 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
8900 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
8901 hlua_class_function(L, "is_full", hlua_channel_is_full);
8902 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008903
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008904 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008905
8906 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008907 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008908
8909 /*
8910 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008911 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008912 *
8913 */
8914
8915 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008916 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008917
Ilya Shipitsind4259502020-04-08 01:07:56 +05008918 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008919 lua_pushstring(L, "__index");
8920 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008921
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008922 /* Browse existing fetches and create the associated
8923 * object method.
8924 */
8925 sf = NULL;
8926 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008927 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
8928 * by an underscore.
8929 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008930 strncpy(trash.area, sf->kw, trash.size);
8931 trash.area[trash.size - 1] = '\0';
8932 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008933 if (*p == '.' || *p == '-' || *p == '+')
8934 *p = '_';
8935
8936 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008937 lua_pushstring(L, trash.area);
8938 lua_pushlightuserdata(L, sf);
8939 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
8940 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008941 }
8942
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008943 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008944
8945 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008946 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008947
8948 /*
8949 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008950 * Register class Converters
8951 *
8952 */
8953
8954 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008955 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008956
8957 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008958 lua_pushstring(L, "__index");
8959 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008960
8961 /* Browse existing converters and create the associated
8962 * object method.
8963 */
8964 sc = NULL;
8965 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008966 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
8967 * by an underscore.
8968 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008969 strncpy(trash.area, sc->kw, trash.size);
8970 trash.area[trash.size - 1] = '\0';
8971 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008972 if (*p == '.' || *p == '-' || *p == '+')
8973 *p = '_';
8974
8975 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008976 lua_pushstring(L, trash.area);
8977 lua_pushlightuserdata(L, sc);
8978 lua_pushcclosure(L, hlua_run_sample_conv, 1);
8979 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008980 }
8981
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008982 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008983
8984 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008985 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008986
8987 /*
8988 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008989 * Register class HTTP
8990 *
8991 */
8992
8993 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008994 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008995
Ilya Shipitsind4259502020-04-08 01:07:56 +05008996 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008997 lua_pushstring(L, "__index");
8998 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008999
9000 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009001 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
9002 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
9003 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
9004 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
9005 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
9006 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
9007 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
9008 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
9009 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
9010 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009011
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009012 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
9013 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
9014 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
9015 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
9016 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
9017 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
9018 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009019
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009020 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009021
9022 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009023 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009024
9025 /*
9026 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009027 * Register class AppletTCP
9028 *
9029 */
9030
9031 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009032 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009033
Ilya Shipitsind4259502020-04-08 01:07:56 +05009034 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009035 lua_pushstring(L, "__index");
9036 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009037
9038 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009039 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
9040 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
9041 hlua_class_function(L, "send", hlua_applet_tcp_send);
9042 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
9043 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
9044 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
9045 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
9046 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009047
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009048 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009049
9050 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009051 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009052
9053 /*
9054 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009055 * Register class AppletHTTP
9056 *
9057 */
9058
9059 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009060 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009061
Ilya Shipitsind4259502020-04-08 01:07:56 +05009062 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009063 lua_pushstring(L, "__index");
9064 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009065
9066 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009067 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
9068 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
9069 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
9070 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
9071 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
9072 hlua_class_function(L, "getline", hlua_applet_http_getline);
9073 hlua_class_function(L, "receive", hlua_applet_http_recv);
9074 hlua_class_function(L, "send", hlua_applet_http_send);
9075 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
9076 hlua_class_function(L, "set_status", hlua_applet_http_status);
9077 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009078
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009079 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009080
9081 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009082 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009083
9084 /*
9085 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009086 * Register class TXN
9087 *
9088 */
9089
9090 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009091 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009092
Ilya Shipitsind4259502020-04-08 01:07:56 +05009093 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009094 lua_pushstring(L, "__index");
9095 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009096
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01009097 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009098 hlua_class_function(L, "set_priv", hlua_set_priv);
9099 hlua_class_function(L, "get_priv", hlua_get_priv);
9100 hlua_class_function(L, "set_var", hlua_set_var);
9101 hlua_class_function(L, "unset_var", hlua_unset_var);
9102 hlua_class_function(L, "get_var", hlua_get_var);
9103 hlua_class_function(L, "done", hlua_txn_done);
9104 hlua_class_function(L, "reply", hlua_txn_reply_new);
9105 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
9106 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
9107 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
9108 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
9109 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
9110 hlua_class_function(L, "deflog", hlua_txn_deflog);
9111 hlua_class_function(L, "log", hlua_txn_log);
9112 hlua_class_function(L, "Debug", hlua_txn_log_debug);
9113 hlua_class_function(L, "Info", hlua_txn_log_info);
9114 hlua_class_function(L, "Warning", hlua_txn_log_warning);
9115 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01009116
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009117 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009118
9119 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009120 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009121
9122 /*
9123 *
Christopher Faulet700d9e82020-01-31 12:21:52 +01009124 * Register class reply
9125 *
9126 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009127 lua_newtable(L);
9128 lua_pushstring(L, "__index");
9129 lua_newtable(L);
9130 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
9131 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
9132 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
9133 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
9134 lua_settable(L, -3); /* Sets the __index entry. */
9135 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +01009136
9137
9138 /*
9139 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009140 * Register class Socket
9141 *
9142 */
9143
9144 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009145 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009146
Ilya Shipitsind4259502020-04-08 01:07:56 +05009147 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009148 lua_pushstring(L, "__index");
9149 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009150
Baptiste Assmann84bb4932015-03-02 21:40:06 +01009151#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009152 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +01009153#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009154 hlua_class_function(L, "connect", hlua_socket_connect);
9155 hlua_class_function(L, "send", hlua_socket_send);
9156 hlua_class_function(L, "receive", hlua_socket_receive);
9157 hlua_class_function(L, "close", hlua_socket_close);
9158 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
9159 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
9160 hlua_class_function(L, "setoption", hlua_socket_setoption);
9161 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009162
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009163 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009164
9165 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009166 lua_pushstring(L, "__gc");
9167 lua_pushcclosure(L, hlua_socket_gc, 0);
9168 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009169
9170 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009171 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009172
Thierry Fournieraafc7772020-12-04 11:47:47 +01009173 lua_atpanic(L, hlua_panic_safe);
9174
9175 return L;
9176}
9177
9178void hlua_init(void) {
9179 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01009180 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +01009181#ifdef USE_OPENSSL
9182 struct srv_kw *kw;
9183 int tmp_error;
9184 char *error;
9185 char *args[] = { /* SSL client configuration. */
9186 "ssl",
9187 "verify",
9188 "none",
9189 NULL
9190 };
9191#endif
9192
9193 /* Init post init function list head */
9194 for (i = 0; i < MAX_THREADS + 1; i++)
9195 LIST_INIT(&hlua_init_functions[i]);
9196
9197 /* Init state for common/shared lua parts */
9198 hlua_state_id = 0;
9199 ha_set_tid(0);
9200 hlua_states[0] = hlua_init_state(0);
9201
9202 /* Init state 1 for thread 0. We have at least one thread. */
9203 hlua_state_id = 1;
9204 ha_set_tid(0);
9205 hlua_states[1] = hlua_init_state(1);
9206
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009207 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +02009208 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01009209 if (!socket_proxy) {
9210 fprintf(stderr, "Lua init: %s\n", errmsg);
9211 exit(1);
9212 }
9213 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009214
9215 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009216 socket_tcp = new_server(socket_proxy);
9217 if (!socket_tcp) {
9218 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
9219 exit(1);
9220 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009221
9222#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009223 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009224 socket_ssl = new_server(socket_proxy);
9225 if (!socket_ssl) {
9226 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
9227 exit(1);
9228 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009229
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009230 socket_ssl->use_ssl = 1;
9231 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009232
Bertrand Jacquin80839ff2021-01-21 19:14:46 +00009233 for (i = 0; args[i] != NULL; i++) {
9234 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009235 /*
9236 *
9237 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009238 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009239 * features like client certificates and ssl_verify.
9240 *
9241 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009242 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009243 if (tmp_error != 0) {
9244 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
9245 abort(); /* This must be never arrives because the command line
9246 not editable by the user. */
9247 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +00009248 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009249 }
9250 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009251#endif
Thierry Fournier75933d42016-01-21 09:30:18 +01009252
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01009253}
Willy Tarreaubb57d942016-12-21 19:04:56 +01009254
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +02009255static void hlua_deinit()
9256{
Willy Tarreau186f3762020-12-04 11:48:12 +01009257 int thr;
9258
9259 for (thr = 0; thr < MAX_THREADS+1; thr++) {
9260 if (hlua_states[thr])
9261 lua_close(hlua_states[thr]);
9262 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +01009263
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009264 free_server(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +01009265
Willy Tarreau0f143af2021-03-05 10:41:48 +01009266#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009267 free_server(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +01009268#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01009269
9270 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +02009271}
9272
9273REGISTER_POST_DEINIT(hlua_deinit);
9274
Willy Tarreau80713382018-11-26 10:19:54 +01009275static void hlua_register_build_options(void)
9276{
Willy Tarreaubb57d942016-12-21 19:04:56 +01009277 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +01009278
Willy Tarreaubb57d942016-12-21 19:04:56 +01009279 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
9280 hap_register_build_opts(ptr, 1);
9281}
Willy Tarreau80713382018-11-26 10:19:54 +01009282
9283INITCALL0(STG_REGISTER, hlua_register_build_options);