blob: be3c1ac03063499e0add7c313b69933c0e63c250 [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 Tarreau55542642021-10-08 09:33:24 +020035#include <haproxy/clock.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020036#include <haproxy/connection.h>
Christopher Faulet69c581a2021-05-31 08:54:04 +020037#include <haproxy/filters.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020038#include <haproxy/h1.h>
Willy Tarreau86416052020-06-04 09:20:54 +020039#include <haproxy/hlua.h>
Willy Tarreau8c794002020-06-04 10:05:25 +020040#include <haproxy/hlua_fcn.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020041#include <haproxy/http_ana.h>
William Lallemand3956c4e2021-09-21 16:25:15 +020042#include <haproxy/http_client.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020043#include <haproxy/http_fetch.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020044#include <haproxy/http_htx.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020045#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020046#include <haproxy/log.h>
Willy Tarreau2cd58092020-06-04 15:10:43 +020047#include <haproxy/map.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020048#include <haproxy/obj_type.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020049#include <haproxy/pattern.h>
Willy Tarreau469509b2020-06-04 15:13:30 +020050#include <haproxy/payload.h>
Willy Tarreau3d6ee402021-05-08 20:28:07 +020051#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020052#include <haproxy/regex.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020053#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020054#include <haproxy/sc_strm.h>
Willy Tarreau198e92a2021-03-05 10:23:32 +010055#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +020056#include <haproxy/session.h>
William Lallemand30fcca12022-03-30 12:03:12 +020057#include <haproxy/ssl_ckch.h>
58#include <haproxy/ssl_sock.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020059#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020060#include <haproxy/stconn.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020061#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020062#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020063#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020064#include <haproxy/thread.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020065#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020066#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020067#include <haproxy/xref.h>
68
Thierry FOURNIER380d0932015-01-23 14:27:52 +010069
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010070/* Lua uses longjmp to perform yield or throwing errors. This
71 * macro is used only for identifying the function that can
72 * not return because a longjmp is executed.
73 * __LJMP marks a prototype of hlua file that can use longjmp.
74 * WILL_LJMP() marks an lua function that will use longjmp.
75 * MAY_LJMP() marks an lua function that may use longjmp.
76 */
77#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020078#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010079#define MAY_LJMP(func) func
80
Thierry FOURNIERbabae282015-09-17 11:36:37 +020081/* This couple of function executes securely some Lua calls outside of
82 * the lua runtime environment. Each Lua call can return a longjmp
83 * if it encounter a memory error.
84 *
85 * Lua documentation extract:
86 *
87 * If an error happens outside any protected environment, Lua calls
88 * a panic function (see lua_atpanic) and then calls abort, thus
89 * exiting the host application. Your panic function can avoid this
90 * exit by never returning (e.g., doing a long jump to your own
91 * recovery point outside Lua).
92 *
93 * The panic function runs as if it were a message handler (see
Willy Tarreau3dfb7da2022-03-02 22:33:39 +010094 * #2.3); in particular, the error message is at the top of the
Thierry FOURNIERbabae282015-09-17 11:36:37 +020095 * stack. However, there is no guarantee about stack space. To push
96 * anything on the stack, the panic function must first check the
Willy Tarreau3dfb7da2022-03-02 22:33:39 +010097 * available space (see #4.2).
Thierry FOURNIERbabae282015-09-17 11:36:37 +020098 *
99 * We must check all the Lua entry point. This includes:
100 * - The include/proto/hlua.h exported functions
101 * - the task wrapper function
102 * - The action wrapper function
103 * - The converters wrapper function
104 * - The sample-fetch wrapper functions
105 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500106 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800107 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200108 *
109 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
110 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
111 * because they must be exists in the program stack when the longjmp
112 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200113 *
114 * Note that the Lua processing is not really thread safe. It provides
115 * heavy system which consists to add our own lock function in the Lua
116 * code and recompile the library. This system will probably not accepted
117 * by maintainers of various distribs.
118 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500119 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200120 * quick looking on the Lua sources displays a lua_lock() a the start
121 * of function and a lua_unlock() at the end of the function. So I
122 * conclude that the Lua thread safe mode just perform a mutex around
123 * all execution. So I prefer to do this in the HAProxy code, it will be
124 * easier for distro maintainers.
125 *
126 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
127 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
128 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200129 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100130__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200131THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200132static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau6a510902021-07-14 19:41:25 +0200133static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); return 0; }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200134
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100135/* This is the chained list of struct hlua_function referenced
136 * for haproxy action, sample-fetches, converters, cli and
137 * applet bindings. It is used for a post-initialisation control.
138 */
139static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
140
Thierry Fournierc7492592020-11-28 23:57:24 +0100141/* This variable is used only during initialization to identify the Lua state
142 * currently being initialized. 0 is the common lua state, 1 to n are the Lua
143 * states dedicated to each thread (in this case hlua_state_id==tid+1).
144 */
145static int hlua_state_id;
146
Thierry Fournier59f11be2020-11-29 00:37:41 +0100147/* This is a NULL-terminated list of lua file which are referenced to load per thread */
Thierry Fournierae6b5682022-09-19 09:04:16 +0200148static char ***per_thread_load = NULL;
Thierry Fournier59f11be2020-11-29 00:37:41 +0100149
150lua_State *hlua_init_state(int thread_id);
151
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200152/* This function takes the Lua global lock. Keep this function's visibility
153 * global so that it can appear in stack dumps and performance profiles!
154 */
155void lua_take_global_lock()
156{
157 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
158}
159
160static inline void lua_drop_global_lock()
161{
162 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
163}
164
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100165#define SET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200166 ({ \
167 int ret; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100168 if ((__HLUA)->state_id == 0) \
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200169 lua_take_global_lock(); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200170 if (setjmp(safe_ljmp_env) != 0) { \
171 lua_atpanic(__L, hlua_panic_safe); \
172 ret = 0; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100173 if ((__HLUA)->state_id == 0) \
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200174 lua_drop_global_lock(); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200175 } else { \
176 lua_atpanic(__L, hlua_panic_ljmp); \
177 ret = 1; \
178 } \
179 ret; \
180 })
181
182/* If we are the last function catching Lua errors, we
183 * must reset the panic function.
184 */
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100185#define RESET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200186 do { \
187 lua_atpanic(__L, hlua_panic_safe); \
Thierry Fournier021d9862020-11-28 23:42:03 +0100188 if ((__HLUA)->state_id == 0) \
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200189 lua_drop_global_lock(); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200190 } while(0)
191
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100192#define SET_SAFE_LJMP(__HLUA) \
193 SET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
194
195#define RESET_SAFE_LJMP(__HLUA) \
196 RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
197
198#define SET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100199 SET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100200
201#define RESET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100202 RESET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100203
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200204/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200205#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100206/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200207#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200208/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100209#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100210#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200211
Thierry Fournierafc63e22020-11-28 17:06:51 +0100212/* The main Lua execution context. The 0 index is the
213 * common state shared by all threads.
214 */
Willy Tarreau186f3762020-12-04 11:48:12 +0100215static lua_State *hlua_states[MAX_THREADS + 1];
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100216
Christopher Fauletc404f112020-02-26 15:03:09 +0100217#define HLUA_FLT_CB_FINAL 0x00000001
218#define HLUA_FLT_CB_RETVAL 0x00000002
219#define HLUA_FLT_CB_ARG_CHN 0x00000004
220#define HLUA_FLT_CB_ARG_HTTP_MSG 0x00000008
221
Christopher Faulet9f55a502020-02-25 15:21:02 +0100222#define HLUA_FLT_CTX_FL_PAYLOAD 0x00000001
223
Christopher Faulet69c581a2021-05-31 08:54:04 +0200224struct hlua_reg_filter {
225 char *name;
226 int flt_ref[MAX_THREADS + 1];
227 int fun_ref[MAX_THREADS + 1];
228 struct list l;
229};
230
231struct hlua_flt_config {
232 struct hlua_reg_filter *reg;
233 int ref[MAX_THREADS + 1];
234 char **args;
235};
236
237struct hlua_flt_ctx {
238 int ref; /* ref to the filter lua object */
239 struct hlua *hlua[2]; /* lua runtime context (0: request, 1: response) */
240 unsigned int cur_off[2]; /* current offset (0: request, 1: response) */
241 unsigned int cur_len[2]; /* current forwardable length (0: request, 1: response) */
242 unsigned int flags; /* HLUA_FLT_CTX_FL_* */
243};
244
Willy Tarreau5321da92022-05-06 11:57:34 +0200245/* appctx context used by the cosockets */
246struct hlua_csk_ctx {
247 int connected;
248 struct xref xref; /* cross reference with the Lua object owner. */
249 struct list wake_on_read;
250 struct list wake_on_write;
251 struct appctx *appctx;
252 int die;
253};
254
Willy Tarreaue23f33b2022-05-06 14:07:13 +0200255/* appctx context used by TCP services */
256struct hlua_tcp_ctx {
257 struct hlua *hlua;
258 int flags;
259 struct task *task;
260};
261
Willy Tarreauaa229cc2022-05-06 14:26:10 +0200262/* appctx context used by HTTP services */
263struct hlua_http_ctx {
264 struct hlua *hlua;
265 int left_bytes; /* The max amount of bytes that we can read. */
266 int flags;
267 int status;
268 const char *reason;
269 struct task *task;
270};
271
Willy Tarreaubcda5f62022-05-03 18:13:39 +0200272/* used by registered CLI keywords */
273struct hlua_cli_ctx {
274 struct hlua *hlua;
275 struct task *task;
276 struct hlua_function *fcn;
277};
278
Christopher Faulet69c581a2021-05-31 08:54:04 +0200279DECLARE_STATIC_POOL(pool_head_hlua_flt_ctx, "hlua_flt_ctx", sizeof(struct hlua_flt_ctx));
280
Christopher Faulet9f55a502020-02-25 15:21:02 +0100281static int hlua_filter_from_payload(struct filter *filter);
282
Christopher Faulet69c581a2021-05-31 08:54:04 +0200283/* This is the chained list of struct hlua_flt referenced
284 * for haproxy filters. It is used for a post-initialisation control.
285 */
286static struct list referenced_filters = LIST_HEAD_INIT(referenced_filters);
287
288
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100289/* This is the memory pool containing struct lua for applets
290 * (including cli).
291 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100292DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100293
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100294/* Used for Socket connection. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +0100295static struct proxy *socket_proxy;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100296static struct server *socket_tcp;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100297#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100298static struct server *socket_ssl;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100299#endif
300
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100301/* List head of the function called at the initialisation time. */
Thierry Fournierc7492592020-11-28 23:57:24 +0100302struct list hlua_init_functions[MAX_THREADS + 1];
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100303
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100304/* The following variables contains the reference of the different
305 * Lua classes. These references are useful for identify metadata
306 * associated with an object.
307 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100308static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100309static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100310static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100311static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100312static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100313static int class_http_ref;
Christopher Fauletdf97ac42020-02-26 16:57:19 +0100314static int class_http_msg_ref;
William Lallemand3956c4e2021-09-21 16:25:15 +0200315static int class_httpclient_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200316static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200317static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200318static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100319static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100320
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100321/* Global Lua execution timeout. By default Lua, execution linked
Willy Tarreau87b09662015-04-03 00:22:06 +0200322 * with stream (actions, sample-fetches and converters) have a
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100323 * short timeout. Lua linked with tasks doesn't have a timeout
324 * because a task may remain alive during all the haproxy execution.
325 */
326static unsigned int hlua_timeout_session = 4000; /* session timeout. */
327static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200328static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100329
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100330/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
331 * it is used for preventing infinite loops.
332 *
333 * I test the scheer with an infinite loop containing one incrementation
334 * and one test. I run this loop between 10 seconds, I raise a ceil of
335 * 710M loops from one interrupt each 9000 instructions, so I fix the value
336 * to one interrupt each 10 000 instructions.
337 *
338 * configured | Number of
339 * instructions | loops executed
340 * between two | in milions
341 * forced yields |
342 * ---------------+---------------
343 * 10 | 160
344 * 500 | 670
345 * 1000 | 680
346 * 5000 | 700
347 * 7000 | 700
348 * 8000 | 700
349 * 9000 | 710 <- ceil
350 * 10000 | 710
351 * 100000 | 710
352 * 1000000 | 710
353 *
354 */
355static unsigned int hlua_nb_instruction = 10000;
356
Willy Tarreaucdb53462020-12-02 12:12:00 +0100357/* Descriptor for the memory allocation state. The limit is pre-initialised to
358 * 0 until it is replaced by "tune.lua.maxmem" during the config parsing, or it
359 * is replaced with ~0 during post_init after everything was loaded. This way
360 * it is guaranteed that if limit is ~0 the boot is complete and that if it's
361 * zero it's not yet limited and proper accounting is required.
Willy Tarreau32f61e22015-03-18 17:54:59 +0100362 */
363struct hlua_mem_allocator {
364 size_t allocated;
365 size_t limit;
366};
367
Willy Tarreaucdb53462020-12-02 12:12:00 +0100368static struct hlua_mem_allocator hlua_global_allocator THREAD_ALIGNED(64);
Willy Tarreau32f61e22015-03-18 17:54:59 +0100369
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100370/* These functions converts types between HAProxy internal args or
371 * sample and LUA types. Another function permits to check if the
372 * LUA stack contains arguments according with an required ARG_T
373 * format.
374 */
375static int hlua_arg2lua(lua_State *L, const struct arg *arg);
376static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100377__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100378 uint64_t mask, struct proxy *p);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100379static int hlua_smp2lua(lua_State *L, struct sample *smp);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100380static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100381static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
382
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100383__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200384
Thierry Fournier59f11be2020-11-29 00:37:41 +0100385struct prepend_path {
386 struct list l;
387 char *type;
388 char *path;
389};
390
391static struct list prepend_path_list = LIST_HEAD_INIT(prepend_path_list);
392
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200393#define SEND_ERR(__be, __fmt, __args...) \
394 do { \
395 send_log(__be, LOG_ERR, __fmt, ## __args); \
396 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100397 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200398 } while (0)
399
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100400static inline struct hlua_function *new_hlua_function()
401{
402 struct hlua_function *fcn;
Thierry Fournierc7492592020-11-28 23:57:24 +0100403 int i;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100404
405 fcn = calloc(1, sizeof(*fcn));
406 if (!fcn)
407 return NULL;
Willy Tarreau2b718102021-04-21 07:32:39 +0200408 LIST_APPEND(&referenced_functions, &fcn->l);
Thierry Fournierc7492592020-11-28 23:57:24 +0100409 for (i = 0; i < MAX_THREADS + 1; i++)
410 fcn->function_ref[i] = -1;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100411 return fcn;
412}
413
Christopher Fauletdda44442021-04-12 14:05:43 +0200414static inline void release_hlua_function(struct hlua_function *fcn)
415{
416 if (!fcn)
417 return;
418 if (fcn->name)
419 ha_free(&fcn->name);
Willy Tarreau2b718102021-04-21 07:32:39 +0200420 LIST_DELETE(&fcn->l);
Christopher Fauletdda44442021-04-12 14:05:43 +0200421 ha_free(&fcn);
422}
423
Thierry Fournierc7492592020-11-28 23:57:24 +0100424/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
425static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
426{
427 if (fcn->function_ref[0] == -1)
428 return tid + 1;
429 return 0;
430}
431
Christopher Faulet69c581a2021-05-31 08:54:04 +0200432/* Create a new registered filter. Only its name is filled */
433static inline struct hlua_reg_filter *new_hlua_reg_filter(const char *name)
434{
435 struct hlua_reg_filter *reg_flt;
436 int i;
437
438 reg_flt = calloc(1, sizeof(*reg_flt));
439 if (!reg_flt)
440 return NULL;
441 reg_flt->name = strdup(name);
442 if (!reg_flt->name) {
443 free(reg_flt);
444 return NULL;
445 }
446 LIST_APPEND(&referenced_filters, &reg_flt->l);
447 for (i = 0; i < MAX_THREADS + 1; i++) {
448 reg_flt->flt_ref[i] = -1;
449 reg_flt->fun_ref[i] = -1;
450 }
451 return reg_flt;
452}
453
454/* Release a registered filter */
455static inline void release_hlua_reg_filter(struct hlua_reg_filter *reg_flt)
456{
457 if (!reg_flt)
458 return;
459 if (reg_flt->name)
460 ha_free(&reg_flt->name);
461 LIST_DELETE(&reg_flt->l);
462 ha_free(&reg_flt);
463}
464
465/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
466static inline int reg_flt_to_stack_id(struct hlua_reg_filter *reg_flt)
467{
468 if (reg_flt->fun_ref[0] == -1)
469 return tid + 1;
470 return 0;
471}
472
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100473/* Used to check an Lua function type in the stack. It creates and
474 * returns a reference of the function. This function throws an
475 * error if the rgument is not a "function".
476 */
477__LJMP unsigned int hlua_checkfunction(lua_State *L, int argno)
478{
479 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100480 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100481 WILL_LJMP(luaL_argerror(L, argno, msg));
482 }
483 lua_pushvalue(L, argno);
484 return luaL_ref(L, LUA_REGISTRYINDEX);
485}
486
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100487/* Used to check an Lua table type in the stack. It creates and
488 * returns a reference of the table. This function throws an
489 * error if the rgument is not a "table".
490 */
491__LJMP unsigned int hlua_checktable(lua_State *L, int argno)
492{
493 if (!lua_istable(L, argno)) {
494 const char *msg = lua_pushfstring(L, "table expected, got %s", luaL_typename(L, argno));
495 WILL_LJMP(luaL_argerror(L, argno, msg));
496 }
497 lua_pushvalue(L, argno);
498 return luaL_ref(L, LUA_REGISTRYINDEX);
499}
500
Christopher Fauletd09cc512021-03-24 14:48:45 +0100501__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200502{
503 lua_Debug ar;
504 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200505 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200506
507 while (lua_getstack(L, level++, &ar)) {
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200508 /* Fill fields:
509 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
510 * 'l': fills in the field currentline;
511 * 'n': fills in the field name and namewhat;
512 * 't': fills in the field istailcall;
513 */
514 lua_getinfo(L, "Slnt", &ar);
515
Willy Tarreau5c143402022-06-19 17:35:53 +0200516 /* skip these empty entries, usually they come from deep C functions */
517 if (ar.currentline < 0 && *ar.what == 'C' && !*ar.namewhat && !ar.name)
518 continue;
519
520 /* Add separator */
521 if (b_data(msg))
522 chunk_appendf(msg, "%s", sep);
523
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200524 /* Append code localisation */
525 if (ar.currentline > 0)
Christopher Fauletd09cc512021-03-24 14:48:45 +0100526 chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200527 else
Christopher Fauletd09cc512021-03-24 14:48:45 +0100528 chunk_appendf(msg, "%s: ", ar.short_src);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200529
530 /*
531 * Get function name
532 *
533 * if namewhat is no empty, name is defined.
534 * what contains "Lua" for Lua function, "C" for C function,
535 * or "main" for main code.
536 */
537 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100538 chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200539
540 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100541 chunk_appendf(msg, "in main chunk");
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200542
543 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100544 chunk_appendf(msg, "in function line %d", ar.linedefined);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200545
546 else /* nothing left... */
547 chunk_appendf(msg, "?");
548
549
550 /* Display tailed call */
551 if (ar.istailcall)
552 chunk_appendf(msg, " ...");
553 }
554
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200555 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200556}
557
558
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100559/* This function check the number of arguments available in the
560 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500561 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100562 */
563__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
564{
565 if (lua_gettop(L) == nb)
566 return;
567 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
568}
569
Mark Lakes22154b42018-01-29 14:38:40 -0800570/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100571 * and the line number where the error is encountered.
572 */
573static int hlua_pusherror(lua_State *L, const char *fmt, ...)
574{
575 va_list argp;
576 va_start(argp, fmt);
577 luaL_where(L, 1);
578 lua_pushvfstring(L, fmt, argp);
579 va_end(argp);
580 lua_concat(L, 2);
581 return 1;
582}
583
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100584/* This functions is used with sample fetch and converters. It
585 * converts the HAProxy configuration argument in a lua stack
586 * values.
587 *
588 * It takes an array of "arg", and each entry of the array is
589 * converted and pushed in the LUA stack.
590 */
591static int hlua_arg2lua(lua_State *L, const struct arg *arg)
592{
593 switch (arg->type) {
594 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100595 case ARGT_TIME:
596 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100597 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100598 break;
599
600 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200601 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100602 break;
603
604 case ARGT_IPV4:
605 case ARGT_IPV6:
606 case ARGT_MSK4:
607 case ARGT_MSK6:
608 case ARGT_FE:
609 case ARGT_BE:
610 case ARGT_TAB:
611 case ARGT_SRV:
612 case ARGT_USR:
613 case ARGT_MAP:
614 default:
615 lua_pushnil(L);
616 break;
617 }
618 return 1;
619}
620
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500621/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100622 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500623 * with sample fetch wrappers. The input arguments are given to the
624 * lua wrapper and converted as arg list by the function.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100625 */
626static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
627{
628 switch (lua_type(L, ud)) {
629
630 case LUA_TNUMBER:
631 case LUA_TBOOLEAN:
632 arg->type = ARGT_SINT;
633 arg->data.sint = lua_tointeger(L, ud);
634 break;
635
636 case LUA_TSTRING:
637 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200638 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200639 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200640 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200641 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100642 break;
643
644 case LUA_TUSERDATA:
645 case LUA_TNIL:
646 case LUA_TTABLE:
647 case LUA_TFUNCTION:
648 case LUA_TTHREAD:
649 case LUA_TLIGHTUSERDATA:
650 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200651 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100652 break;
653 }
654 return 1;
655}
656
657/* the following functions are used to convert a struct sample
658 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500659 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100660 */
Willy Tarreau5eadada2015-03-10 17:28:54 +0100661static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100662{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200663 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100664 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100665 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200666 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100667 break;
668
669 case SMP_T_BIN:
670 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200671 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100672 break;
673
674 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200675 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100676 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
677 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
678 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
679 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
680 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
681 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
682 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
683 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
684 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200685 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100686 break;
687 default:
688 lua_pushnil(L);
689 break;
690 }
691 break;
692
693 case SMP_T_IPV4:
694 case SMP_T_IPV6:
695 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200696 if (sample_casts[smp->data.type][SMP_T_STR] &&
697 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200698 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100699 else
700 lua_pushnil(L);
701 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100702 default:
703 lua_pushnil(L);
704 break;
705 }
706 return 1;
707}
708
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100709/* the following functions are used to convert a struct sample
710 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500711 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100712 */
713static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
714{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200715 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100716
717 case SMP_T_BIN:
718 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200719 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100720 break;
721
722 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200723 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100724 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
725 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
726 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
727 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
728 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
729 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
730 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
731 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
732 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200733 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100734 break;
735 default:
736 lua_pushstring(L, "");
737 break;
738 }
739 break;
740
741 case SMP_T_SINT:
742 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100743 case SMP_T_IPV4:
744 case SMP_T_IPV6:
745 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200746 if (sample_casts[smp->data.type][SMP_T_STR] &&
747 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200748 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100749 else
750 lua_pushstring(L, "");
751 break;
752 default:
753 lua_pushstring(L, "");
754 break;
755 }
756 return 1;
757}
758
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100759/* the following functions are used to convert an Lua type in a
760 * struct sample. This is useful to provide data from a converter
761 * to the LUA code.
762 */
763static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
764{
765 switch (lua_type(L, ud)) {
766
767 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200768 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200769 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100770 break;
771
772
773 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200774 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200775 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100776 break;
777
778 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200779 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100780 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200781 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200782 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200783 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200784 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100785 break;
786
787 case LUA_TUSERDATA:
788 case LUA_TNIL:
789 case LUA_TTABLE:
790 case LUA_TFUNCTION:
791 case LUA_TTHREAD:
792 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +0200793 case LUA_TNONE:
794 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200795 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200796 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100797 break;
798 }
799 return 1;
800}
801
Ilya Shipitsind4259502020-04-08 01:07:56 +0500802/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800803 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100804 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100805 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500806 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Willy Tarreauee0d7272021-07-16 10:26:56 +0200807 * entries and that there is at least one stop at the last position.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100808 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100809__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100810 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100811{
812 int min_arg;
Willy Tarreauee0d7272021-07-16 10:26:56 +0200813 int idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100814 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +0200815 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200816 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200817 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200818 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100819
820 idx = 0;
821 min_arg = ARGM(mask);
822 mask >>= ARGM_BITS;
823
824 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200825 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100826
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100827 /* Check for mandatory arguments. */
828 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100829 if (idx < min_arg) {
830
831 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200832 if (idx > 0) {
833 msg = "Mandatory argument expected";
834 goto error;
835 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100836
837 /* If first argument have a certain type, some default values
838 * may be used. See the function smp_resolve_args().
839 */
840 switch (mask & ARGT_MASK) {
841
842 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200843 if (!(p->cap & PR_CAP_FE)) {
844 msg = "Mandatory argument expected";
845 goto error;
846 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100847 argp[idx].data.prx = p;
848 argp[idx].type = ARGT_FE;
849 argp[idx+1].type = ARGT_STOP;
850 break;
851
852 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200853 if (!(p->cap & PR_CAP_BE)) {
854 msg = "Mandatory argument expected";
855 goto error;
856 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100857 argp[idx].data.prx = p;
858 argp[idx].type = ARGT_BE;
859 argp[idx+1].type = ARGT_STOP;
860 break;
861
862 case ARGT_TAB:
Olivier Houchard14f62682022-09-13 00:35:53 +0200863 if (!p->table) {
864 msg = "Mandatory argument expected";
865 goto error;
866 }
867 argp[idx].data.t = p->table;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100868 argp[idx].type = ARGT_TAB;
869 argp[idx+1].type = ARGT_STOP;
870 break;
871
872 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200873 msg = "Mandatory argument expected";
874 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100875 break;
876 }
877 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200878 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100879 }
880
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500881 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100882 if ((mask & ARGT_MASK) == ARGT_STOP &&
883 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200884 msg = "Last argument expected";
885 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100886 }
887
888 if ((mask & ARGT_MASK) == ARGT_STOP &&
889 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200890 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100891 }
892
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200893 /* Convert some argument types. All string in argp[] are for not
894 * duplicated yet.
895 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100896 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100897 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200898 if (argp[idx].type != ARGT_SINT) {
899 msg = "integer expected";
900 goto error;
901 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100902 argp[idx].type = ARGT_SINT;
903 break;
904
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100905 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200906 if (argp[idx].type != ARGT_SINT) {
907 msg = "integer expected";
908 goto error;
909 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200910 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100911 break;
912
913 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200914 if (argp[idx].type != ARGT_SINT) {
915 msg = "integer expected";
916 goto error;
917 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200918 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100919 break;
920
921 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200922 if (argp[idx].type != ARGT_STR) {
923 msg = "string expected";
924 goto error;
925 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200926 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200927 if (!argp[idx].data.prx) {
928 msg = "frontend doesn't exist";
929 goto error;
930 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100931 argp[idx].type = ARGT_FE;
932 break;
933
934 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200935 if (argp[idx].type != ARGT_STR) {
936 msg = "string expected";
937 goto error;
938 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200939 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200940 if (!argp[idx].data.prx) {
941 msg = "backend doesn't exist";
942 goto error;
943 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100944 argp[idx].type = ARGT_BE;
945 break;
946
947 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200948 if (argp[idx].type != ARGT_STR) {
949 msg = "string expected";
950 goto error;
951 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200952 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200953 if (!argp[idx].data.t) {
954 msg = "table doesn't exist";
955 goto error;
956 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100957 argp[idx].type = ARGT_TAB;
958 break;
959
960 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200961 if (argp[idx].type != ARGT_STR) {
962 msg = "string expected";
963 goto error;
964 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200965 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100966 if (sname) {
967 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200968 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +0200969 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200970 if (!px) {
971 msg = "backend doesn't exist";
972 goto error;
973 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100974 }
975 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200976 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100977 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100978 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100979 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200980 if (!argp[idx].data.srv) {
981 msg = "server doesn't exist";
982 goto error;
983 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100984 argp[idx].type = ARGT_SRV;
985 break;
986
987 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200988 if (argp[idx].type != ARGT_STR) {
989 msg = "string expected";
990 goto error;
991 }
992 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
993 msg = "invalid IPv4 address";
994 goto error;
995 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100996 argp[idx].type = ARGT_IPV4;
997 break;
998
999 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +02001000 if (argp[idx].type == ARGT_SINT)
1001 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
1002 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001003 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
1004 msg = "invalid IPv4 mask";
1005 goto error;
1006 }
1007 }
1008 else {
1009 msg = "integer or string expected";
1010 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +02001011 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001012 argp[idx].type = ARGT_MSK4;
1013 break;
1014
1015 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001016 if (argp[idx].type != ARGT_STR) {
1017 msg = "string expected";
1018 goto error;
1019 }
1020 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
1021 msg = "invalid IPv6 address";
1022 goto error;
1023 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001024 argp[idx].type = ARGT_IPV6;
1025 break;
1026
1027 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +02001028 if (argp[idx].type == ARGT_SINT)
1029 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
1030 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001031 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
1032 msg = "invalid IPv6 mask";
1033 goto error;
1034 }
1035 }
1036 else {
1037 msg = "integer or string expected";
1038 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +02001039 }
Tim Duesterhusb814da62018-01-25 16:24:50 +01001040 argp[idx].type = ARGT_MSK6;
1041 break;
1042
Christopher Fauletfd2e9062020-08-06 11:10:57 +02001043 case ARGT_REG:
1044 if (argp[idx].type != ARGT_STR) {
1045 msg = "string expected";
1046 goto error;
1047 }
1048 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
1049 if (!reg) {
1050 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
1051 argp[idx].data.str.area, err);
1052 free(err);
1053 goto error;
1054 }
1055 argp[idx].type = ARGT_REG;
1056 argp[idx].data.reg = reg;
1057 break;
1058
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001059 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001060 if (argp[idx].type != ARGT_STR) {
1061 msg = "string expected";
1062 goto error;
1063 }
1064 if (p->uri_auth && p->uri_auth->userlist &&
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001065 strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area) == 0)
Christopher Fauletd25d9262020-08-06 11:04:46 +02001066 ul = p->uri_auth->userlist;
1067 else
1068 ul = auth_find_userlist(argp[idx].data.str.area);
1069
1070 if (!ul) {
1071 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
1072 goto error;
1073 }
1074 argp[idx].type = ARGT_USR;
1075 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001076 break;
1077
1078 case ARGT_STR:
1079 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
1080 msg = "unable to duplicate string arg";
1081 goto error;
1082 }
1083 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001084 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001085
Christopher Fauletd25d9262020-08-06 11:04:46 +02001086 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001087 msg = "type not yet supported";
1088 goto error;
1089 break;
1090
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001091 }
1092
1093 /* Check for type of argument. */
1094 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001095 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
1096 arg_type_names[(mask & ARGT_MASK)],
1097 arg_type_names[argp[idx].type & ARGT_MASK]);
1098 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001099 }
1100
1101 /* Next argument. */
1102 mask >>= ARGT_BITS;
1103 idx++;
1104 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001105 return 0;
1106
1107 error:
Olivier Houchardca431612022-09-13 00:31:17 +02001108 argp[idx].type = ARGT_STOP;
Willy Tarreauee0d7272021-07-16 10:26:56 +02001109 free_args(argp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001110 WILL_LJMP(luaL_argerror(L, first + idx, msg));
1111 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001112}
1113
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001114/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001115 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001116 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001117 *
1118 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001119 * - hlua_sethlua : create the association between hlua context and lua_state.
1120 */
1121static inline struct hlua *hlua_gethlua(lua_State *L)
1122{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001123 struct hlua **hlua = lua_getextraspace(L);
1124 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001125}
1126static inline void hlua_sethlua(struct hlua *hlua)
1127{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001128 struct hlua **hlua_store = lua_getextraspace(hlua->T);
1129 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001130}
1131
Willy Tarreau0b7b6392022-06-19 17:39:33 +02001132/* Will return a non-NULL string indicating the Lua call trace if the caller
1133 * currently is executing from within a Lua function. One line per entry will
1134 * be emitted, and each extra line will be prefixed with <pfx>. If a current
1135 * Lua function is not detected, NULL is returned.
1136 */
1137const char *hlua_show_current_location(const char *pfx)
1138{
1139 lua_State *L;
1140 lua_Debug ar;
1141
1142 /* global or per-thread stack initializing ? */
1143 if (hlua_state_id != -1 && (L = hlua_states[hlua_state_id]) && lua_getstack(L, 0, &ar))
1144 return hlua_traceback(L, pfx);
1145
1146 /* per-thread stack running ? */
1147 if (hlua_states[tid + 1] && (L = hlua_states[tid + 1]) && lua_getstack(L, 0, &ar))
1148 return hlua_traceback(L, pfx);
1149
1150 /* global stack running ? */
1151 if (hlua_states[0] && (L = hlua_states[0]) && lua_getstack(L, 0, &ar))
1152 return hlua_traceback(L, pfx);
1153
1154 return NULL;
1155}
1156
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001157/* This function is used to send logs. It try to send on screen (stderr)
1158 * and on the default syslog server.
1159 */
1160static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
1161{
1162 struct tm tm;
1163 char *p;
1164
1165 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001166 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001167 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001168 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +02001169 /* Break the message if exceed the buffer size. */
1170 *(p-4) = ' ';
1171 *(p-3) = '.';
1172 *(p-2) = '.';
1173 *(p-1) = '.';
1174 break;
1175 }
Willy Tarreau90807112020-02-25 08:16:33 +01001176 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001177 *p = *msg;
1178 else
1179 *p = '.';
1180 }
1181 *p = '\0';
1182
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001183 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001184 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +02001185 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
1186 return;
1187
Willy Tarreaua678b432015-08-28 10:14:59 +02001188 get_localtime(date.tv_sec, &tm);
1189 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001190 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001191 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001192 fflush(stderr);
1193 }
1194}
1195
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001196/* This function just ensure that the yield will be always
1197 * returned with a timeout and permit to set some flags
1198 */
1199__LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001200 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001201{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001202 struct hlua *hlua;
1203
1204 /* Get hlua struct, or NULL if we execute from main lua state */
1205 hlua = hlua_gethlua(L);
1206 if (!hlua) {
1207 return;
1208 }
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001209
1210 /* Set the wake timeout. If timeout is required, we set
1211 * the expiration time.
1212 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001213 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001214
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +01001215 hlua->flags |= flags;
1216
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001217 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +02001218 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001219}
1220
Willy Tarreau87b09662015-04-03 00:22:06 +02001221/* This function initialises the Lua environment stored in the stream.
1222 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001223 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001224 *
1225 * This function is particular. it initialises a new Lua thread. If the
1226 * initialisation fails (example: out of memory error), the lua function
1227 * throws an error (longjmp).
1228 *
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001229 * In some case (at least one), this function can be called from safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001230 * environment, so we must not initialise it. While the support of
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001231 * threads appear, the safe environment set a lock to ensure only one
1232 * Lua execution at a time. If we initialize safe environment in another
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001233 * safe environment, we have a dead lock.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001234 *
1235 * set "already_safe" true if the context is initialized form safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001236 * Lua function.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001237 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001238 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001239 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001240 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001241 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001242 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001243int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already_safe)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001244{
1245 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001246 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001247 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001248 lua->wake_time = TICK_ETERNITY;
Thierry Fournier021d9862020-11-28 23:42:03 +01001249 lua->state_id = state_id;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001250 LIST_INIT(&lua->com);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001251 MT_LIST_INIT(&lua->hc_list);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001252 if (!already_safe) {
1253 if (!SET_SAFE_LJMP_PARENT(lua)) {
1254 lua->Tref = LUA_REFNIL;
1255 return 0;
1256 }
1257 }
Thierry Fournier021d9862020-11-28 23:42:03 +01001258 lua->T = lua_newthread(hlua_states[state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001259 if (!lua->T) {
1260 lua->Tref = LUA_REFNIL;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001261 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001262 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001263 return 0;
1264 }
1265 hlua_sethlua(lua);
Thierry Fournier021d9862020-11-28 23:42:03 +01001266 lua->Tref = luaL_ref(hlua_states[state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001267 lua->task = task;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001268 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001269 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001270 return 1;
1271}
1272
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001273/* kill all associated httpclient to this hlua task
1274 * We must take extra precautions as we're manipulating lua-exposed
1275 * objects without the main lua lock.
1276 */
William Lallemandbb581422022-10-20 10:57:28 +02001277static void hlua_httpclient_destroy_all(struct hlua *hlua)
1278{
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001279 struct hlua_httpclient *hlua_hc;
William Lallemandbb581422022-10-20 10:57:28 +02001280
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001281 /* use thread-safe accessors for hc_list since GC cycle initiated by
1282 * another thread sharing the same main lua stack (lua coroutine)
1283 * could execute hlua_httpclient_gc() on the hlua->hc_list items
1284 * in parallel: Lua GC applies on the main stack, it is not limited to
1285 * a single coroutine stack, see Github issue #2037 for reference.
1286 * Remember, coroutines created using lua_newthread() are not meant to
1287 * be thread safe in Lua. (From lua co-author:
1288 * http://lua-users.org/lists/lua-l/2011-07/msg00072.html)
1289 *
1290 * This security measure is superfluous when 'lua-load-per-thread' is used
1291 * since in this case coroutines exclusively run on the same thread
1292 * (main stack is not shared between OS threads).
1293 */
1294 while ((hlua_hc = MT_LIST_POP(&hlua->hc_list, typeof(hlua_hc), by_hlua))) {
1295 httpclient_stop_and_destroy(hlua_hc->hc);
William Lallemandbb581422022-10-20 10:57:28 +02001296 hlua_hc->hc = NULL;
William Lallemandbb581422022-10-20 10:57:28 +02001297 }
1298}
1299
1300
Willy Tarreau87b09662015-04-03 00:22:06 +02001301/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001302 * is destroyed. The destroy also the memory context. The struct "lua"
1303 * is not freed.
1304 */
1305void hlua_ctx_destroy(struct hlua *lua)
1306{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001307 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001308 return;
1309
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001310 if (!lua->T)
1311 goto end;
1312
William Lallemandbb581422022-10-20 10:57:28 +02001313 /* clean all running httpclient */
1314 hlua_httpclient_destroy_all(lua);
1315
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001316 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001317 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001318
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001319 if (!SET_SAFE_LJMP(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001320 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001321 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001322 RESET_SAFE_LJMP(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001323
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001324 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001325 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001326 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001327 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001328 /* Forces a garbage collecting process. If the Lua program is finished
1329 * without error, we run the GC on the thread pointer. Its freed all
1330 * the unused memory.
1331 * If the thread is finnish with an error or is currently yielded,
1332 * it seems that the GC applied on the thread doesn't clean anything,
1333 * so e run the GC on the main thread.
1334 * NOTE: maybe this action locks all the Lua threads untiml the en of
1335 * the garbage collection.
1336 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001337 if (lua->gc_count) {
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001338 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001339 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001340 lua_gc(hlua_states[lua->state_id], LUA_GCCOLLECT, 0);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001341 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001342 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001343
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001344 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001345
1346end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001347 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001348}
1349
1350/* This function is used to restore the Lua context when a coroutine
1351 * fails. This function copy the common memory between old coroutine
1352 * and the new coroutine. The old coroutine is destroyed, and its
1353 * replaced by the new coroutine.
1354 * If the flag "keep_msg" is set, the last entry of the old is assumed
1355 * as string error message and it is copied in the new stack.
1356 */
1357static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1358{
1359 lua_State *T;
1360 int new_ref;
1361
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001362 /* New Lua coroutine. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001363 T = lua_newthread(hlua_states[lua->state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001364 if (!T)
1365 return 0;
1366
1367 /* Copy last error message. */
1368 if (keep_msg)
1369 lua_xmove(lua->T, T, 1);
1370
1371 /* Copy data between the coroutines. */
1372 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1373 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001374 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001375
1376 /* Destroy old data. */
1377 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1378
1379 /* The thread is garbage collected by Lua. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001380 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001381
1382 /* Fill the struct with the new coroutine values. */
1383 lua->Mref = new_ref;
1384 lua->T = T;
Thierry Fournier021d9862020-11-28 23:42:03 +01001385 lua->Tref = luaL_ref(hlua_states[lua->state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001386
1387 /* Set context. */
1388 hlua_sethlua(lua);
1389
1390 return 1;
1391}
1392
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001393void hlua_hook(lua_State *L, lua_Debug *ar)
1394{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001395 struct hlua *hlua;
1396
1397 /* Get hlua struct, or NULL if we execute from main lua state */
1398 hlua = hlua_gethlua(L);
1399 if (!hlua)
1400 return;
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001401
1402 /* Lua cannot yield when its returning from a function,
1403 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001404 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001405 */
1406 if (lua_gethookmask(L) & LUA_MASKRET) {
1407 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1408 return;
1409 }
1410
1411 /* restore the interrupt condition. */
1412 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1413
1414 /* If we interrupt the Lua processing in yieldable state, we yield.
1415 * If the state is not yieldable, trying yield causes an error.
1416 */
1417 if (lua_isyieldable(L))
Willy Tarreau9635e032018-10-16 17:52:55 +02001418 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001419
Thierry FOURNIERa85cfb12015-03-13 14:50:06 +01001420 /* If we cannot yield, update the clock and check the timeout. */
Willy Tarreau55542642021-10-08 09:33:24 +02001421 clock_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001422 hlua->run_time += now_ms - hlua->start_time;
1423 if (hlua->max_time && hlua->run_time >= hlua->max_time) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001424 lua_pushfstring(L, "execution timeout");
1425 WILL_LJMP(lua_error(L));
1426 }
1427
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001428 /* Update the start time. */
1429 hlua->start_time = now_ms;
1430
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001431 /* Try to interrupt the process at the end of the current
1432 * unyieldable function.
1433 */
1434 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001435}
1436
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001437/* This function start or resumes the Lua stack execution. If the flag
1438 * "yield_allowed" if no set and the LUA stack execution returns a yield
1439 * The function return an error.
1440 *
1441 * The function can returns 4 values:
1442 * - HLUA_E_OK : The execution is terminated without any errors.
1443 * - HLUA_E_AGAIN : The execution must continue at the next associated
1444 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001445 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001446 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001447 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001448 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001449 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001450 * LUA code.
1451 */
1452static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1453{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001454#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1455 int nres;
1456#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001457 int ret;
1458 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001459 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001460
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001461 /* Initialise run time counter. */
1462 if (!HLUA_IS_RUNNING(lua))
1463 lua->run_time = 0;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001464
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001465 /* Lock the whole Lua execution. This lock must be before the
1466 * label "resume_execution".
1467 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001468 if (lua->state_id == 0)
Willy Tarreau1e7bef12021-08-20 15:47:25 +02001469 lua_take_global_lock();
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001470
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001471resume_execution:
1472
1473 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1474 * instructions. it is used for preventing infinite loops.
1475 */
1476 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1477
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001478 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001479 HLUA_SET_RUN(lua);
1480 HLUA_CLR_CTRLYIELD(lua);
1481 HLUA_CLR_WAKERESWR(lua);
1482 HLUA_CLR_WAKEREQWR(lua);
Christopher Faulet1f43a342021-08-04 17:58:21 +02001483 HLUA_CLR_NOYIELD(lua);
1484 if (!yield_allowed)
1485 HLUA_SET_NOYIELD(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001486
Christopher Fauletbc275a92020-02-26 14:55:16 +01001487 /* Update the start time and reset wake_time. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001488 lua->start_time = now_ms;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001489 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001490
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001491 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001492#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournier021d9862020-11-28 23:42:03 +01001493 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs, &nres);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001494#else
Thierry Fournier021d9862020-11-28 23:42:03 +01001495 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001496#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001497 switch (ret) {
1498
1499 case LUA_OK:
1500 ret = HLUA_E_OK;
1501 break;
1502
1503 case LUA_YIELD:
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001504 /* Check if the execution timeout is expired. It it is the case, we
1505 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001506 */
Willy Tarreau55542642021-10-08 09:33:24 +02001507 clock_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001508 lua->run_time += now_ms - lua->start_time;
1509 if (lua->max_time && lua->run_time > lua->max_time) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001510 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001511 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001512 break;
1513 }
1514 /* Process the forced yield. if the general yield is not allowed or
1515 * if no task were associated this the current Lua execution
1516 * coroutine, we resume the execution. Else we want to return in the
1517 * scheduler and we want to be waked up again, to continue the
1518 * current Lua execution. So we schedule our own task.
1519 */
1520 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001521 if (!yield_allowed || !lua->task)
1522 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001523 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001524 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001525 if (!yield_allowed) {
1526 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001527 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001528 break;
1529 }
1530 ret = HLUA_E_AGAIN;
1531 break;
1532
1533 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001534
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001535 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001536 * because the errors ares the only one mean to return immediately
1537 * from and lua execution.
1538 */
1539 if (lua->flags & HLUA_EXIT) {
1540 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001541 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001542 break;
1543 }
1544
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001545 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001546 if (!lua_checkstack(lua->T, 1)) {
1547 ret = HLUA_E_ERR;
1548 break;
1549 }
1550 msg = lua_tostring(lua->T, -1);
1551 lua_settop(lua->T, 0); /* Empty the stack. */
1552 lua_pop(lua->T, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01001553 trace = hlua_traceback(lua->T, ", ");
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001554 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001555 lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001556 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001557 lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001558 ret = HLUA_E_ERRMSG;
1559 break;
1560
1561 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001562 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001563 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001564 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001565 break;
1566
1567 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001568 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001569 if (!lua_checkstack(lua->T, 1)) {
1570 ret = HLUA_E_ERR;
1571 break;
1572 }
1573 msg = lua_tostring(lua->T, -1);
1574 lua_settop(lua->T, 0); /* Empty the stack. */
1575 lua_pop(lua->T, 1);
1576 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001577 lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001578 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001579 lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001580 ret = HLUA_E_ERRMSG;
1581 break;
1582
1583 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001584 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001585 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001586 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001587 break;
1588 }
1589
1590 switch (ret) {
1591 case HLUA_E_AGAIN:
1592 break;
1593
1594 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001595 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001596 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001597 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001598 break;
1599
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001600 case HLUA_E_ETMOUT:
1601 case HLUA_E_NOMEM:
1602 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001603 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001604 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001605 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001606 hlua_ctx_renew(lua, 0);
1607 break;
1608
1609 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001610 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001611 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001612 break;
1613 }
1614
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001615 /* This is the main exit point, remove the Lua lock. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001616 if (lua->state_id == 0)
Willy Tarreau1e7bef12021-08-20 15:47:25 +02001617 lua_drop_global_lock();
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001618
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001619 return ret;
1620}
1621
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001622/* This function exit the current code. */
1623__LJMP static int hlua_done(lua_State *L)
1624{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001625 struct hlua *hlua;
1626
1627 /* Get hlua struct, or NULL if we execute from main lua state */
1628 hlua = hlua_gethlua(L);
1629 if (!hlua)
1630 return 0;
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001631
1632 hlua->flags |= HLUA_EXIT;
1633 WILL_LJMP(lua_error(L));
1634
1635 return 0;
1636}
1637
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001638/* This function is an LUA binding. It provides a function
1639 * for deleting ACL from a referenced ACL file.
1640 */
1641__LJMP static int hlua_del_acl(lua_State *L)
1642{
1643 const char *name;
1644 const char *key;
1645 struct pat_ref *ref;
1646
1647 MAY_LJMP(check_args(L, 2, "del_acl"));
1648
1649 name = MAY_LJMP(luaL_checkstring(L, 1));
1650 key = MAY_LJMP(luaL_checkstring(L, 2));
1651
1652 ref = pat_ref_lookup(name);
1653 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001654 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001655
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001656 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001657 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001658 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001659 return 0;
1660}
1661
1662/* This function is an LUA binding. It provides a function
1663 * for deleting map entry from a referenced map file.
1664 */
1665static int hlua_del_map(lua_State *L)
1666{
1667 const char *name;
1668 const char *key;
1669 struct pat_ref *ref;
1670
1671 MAY_LJMP(check_args(L, 2, "del_map"));
1672
1673 name = MAY_LJMP(luaL_checkstring(L, 1));
1674 key = MAY_LJMP(luaL_checkstring(L, 2));
1675
1676 ref = pat_ref_lookup(name);
1677 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001678 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001679
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001680 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001681 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001682 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001683 return 0;
1684}
1685
1686/* This function is an LUA binding. It provides a function
1687 * for adding ACL pattern from a referenced ACL file.
1688 */
1689static int hlua_add_acl(lua_State *L)
1690{
1691 const char *name;
1692 const char *key;
1693 struct pat_ref *ref;
1694
1695 MAY_LJMP(check_args(L, 2, "add_acl"));
1696
1697 name = MAY_LJMP(luaL_checkstring(L, 1));
1698 key = MAY_LJMP(luaL_checkstring(L, 2));
1699
1700 ref = pat_ref_lookup(name);
1701 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001702 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001703
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001704 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001705 if (pat_ref_find_elt(ref, key) == NULL)
1706 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001707 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001708 return 0;
1709}
1710
1711/* This function is an LUA binding. It provides a function
1712 * for setting map pattern and sample from a referenced map
1713 * file.
1714 */
1715static int hlua_set_map(lua_State *L)
1716{
1717 const char *name;
1718 const char *key;
1719 const char *value;
1720 struct pat_ref *ref;
1721
1722 MAY_LJMP(check_args(L, 3, "set_map"));
1723
1724 name = MAY_LJMP(luaL_checkstring(L, 1));
1725 key = MAY_LJMP(luaL_checkstring(L, 2));
1726 value = MAY_LJMP(luaL_checkstring(L, 3));
1727
1728 ref = pat_ref_lookup(name);
1729 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001730 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001731
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001732 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001733 if (pat_ref_find_elt(ref, key) != NULL)
1734 pat_ref_set(ref, key, value, NULL);
1735 else
1736 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001737 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001738 return 0;
1739}
1740
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001741/* A class is a lot of memory that contain data. This data can be a table,
1742 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001743 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001744 * the name of the object (_G[<name>] = <metable> ).
1745 *
1746 * A metable is a table that modify the standard behavior of a standard
1747 * access to the associated data. The entries of this new metatable are
1748 * defined as is:
1749 *
1750 * http://lua-users.org/wiki/MetatableEvents
1751 *
1752 * __index
1753 *
1754 * we access an absent field in a table, the result is nil. This is
1755 * true, but it is not the whole truth. Actually, such access triggers
1756 * the interpreter to look for an __index metamethod: If there is no
1757 * such method, as usually happens, then the access results in nil;
1758 * otherwise, the metamethod will provide the result.
1759 *
1760 * Control 'prototype' inheritance. When accessing "myTable[key]" and
1761 * the key does not appear in the table, but the metatable has an __index
1762 * property:
1763 *
1764 * - if the value is a function, the function is called, passing in the
1765 * table and the key; the return value of that function is returned as
1766 * the result.
1767 *
1768 * - if the value is another table, the value of the key in that table is
1769 * asked for and returned (and if it doesn't exist in that table, but that
1770 * table's metatable has an __index property, then it continues on up)
1771 *
1772 * - Use "rawget(myTable,key)" to skip this metamethod.
1773 *
1774 * http://www.lua.org/pil/13.4.1.html
1775 *
1776 * __newindex
1777 *
1778 * Like __index, but control property assignment.
1779 *
1780 * __mode - Control weak references. A string value with one or both
1781 * of the characters 'k' and 'v' which specifies that the the
1782 * keys and/or values in the table are weak references.
1783 *
1784 * __call - Treat a table like a function. When a table is followed by
1785 * parenthesis such as "myTable( 'foo' )" and the metatable has
1786 * a __call key pointing to a function, that function is invoked
1787 * (passing any specified arguments) and the return value is
1788 * returned.
1789 *
1790 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
1791 * called, if the metatable for myTable has a __metatable
1792 * key, the value of that key is returned instead of the
1793 * actual metatable.
1794 *
1795 * __tostring - Control string representation. When the builtin
1796 * "tostring( myTable )" function is called, if the metatable
1797 * for myTable has a __tostring property set to a function,
1798 * that function is invoked (passing myTable to it) and the
1799 * return value is used as the string representation.
1800 *
1801 * __len - Control table length. When the table length is requested using
1802 * the length operator ( '#' ), if the metatable for myTable has
1803 * a __len key pointing to a function, that function is invoked
1804 * (passing myTable to it) and the return value used as the value
1805 * of "#myTable".
1806 *
1807 * __gc - Userdata finalizer code. When userdata is set to be garbage
1808 * collected, if the metatable has a __gc field pointing to a
1809 * function, that function is first invoked, passing the userdata
1810 * to it. The __gc metamethod is not called for tables.
1811 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
1812 *
1813 * Special metamethods for redefining standard operators:
1814 * http://www.lua.org/pil/13.1.html
1815 *
1816 * __add "+"
1817 * __sub "-"
1818 * __mul "*"
1819 * __div "/"
1820 * __unm "!"
1821 * __pow "^"
1822 * __concat ".."
1823 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001824 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001825 * http://www.lua.org/pil/13.2.html
1826 *
1827 * __eq "=="
1828 * __lt "<"
1829 * __le "<="
1830 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001831
1832/*
1833 *
1834 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001835 * Class Map
1836 *
1837 *
1838 */
1839
1840/* Returns a struct hlua_map if the stack entry "ud" is
1841 * a class session, otherwise it throws an error.
1842 */
1843__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
1844{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001845 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001846}
1847
1848/* This function is the map constructor. It don't need
1849 * the class Map object. It creates and return a new Map
1850 * object. It must be called only during "body" or "init"
1851 * context because it process some filesystem accesses.
1852 */
1853__LJMP static int hlua_map_new(struct lua_State *L)
1854{
1855 const char *fn;
1856 int match = PAT_MATCH_STR;
1857 struct sample_conv conv;
1858 const char *file = "";
1859 int line = 0;
1860 lua_Debug ar;
1861 char *err = NULL;
1862 struct arg args[2];
1863
1864 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
1865 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
1866
1867 fn = MAY_LJMP(luaL_checkstring(L, 1));
1868
1869 if (lua_gettop(L) >= 2) {
1870 match = MAY_LJMP(luaL_checkinteger(L, 2));
1871 if (match < 0 || match >= PAT_MATCH_NUM)
1872 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
1873 }
1874
1875 /* Get Lua filename and line number. */
1876 if (lua_getstack(L, 1, &ar)) { /* check function at level */
1877 lua_getinfo(L, "Sl", &ar); /* get info about it */
1878 if (ar.currentline > 0) { /* is there info? */
1879 file = ar.short_src;
1880 line = ar.currentline;
1881 }
1882 }
1883
1884 /* fill fake sample_conv struct. */
1885 conv.kw = ""; /* unused. */
1886 conv.process = NULL; /* unused. */
1887 conv.arg_mask = 0; /* unused. */
1888 conv.val_args = NULL; /* unused. */
1889 conv.out_type = SMP_T_STR;
1890 conv.private = (void *)(long)match;
1891 switch (match) {
1892 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
1893 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
1894 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
1895 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
1896 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
1897 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
1898 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001899 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001900 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
1901 default:
1902 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
1903 }
1904
1905 /* fill fake args. */
1906 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02001907 args[0].data.str.area = strdup(fn);
1908 args[0].data.str.data = strlen(fn);
1909 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001910 args[1].type = ARGT_STOP;
1911
1912 /* load the map. */
1913 if (!sample_load_map(args, &conv, file, line, &err)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001914 /* error case: we can't use luaL_error because we must
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001915 * free the err variable.
1916 */
1917 luaL_where(L, 1);
1918 lua_pushfstring(L, "'new': %s.", err);
1919 lua_concat(L, 2);
1920 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001921 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001922 WILL_LJMP(lua_error(L));
1923 }
1924
1925 /* create the lua object. */
1926 lua_newtable(L);
1927 lua_pushlightuserdata(L, args[0].data.map);
1928 lua_rawseti(L, -2, 0);
1929
1930 /* Pop a class Map metatable and affect it to the userdata. */
1931 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
1932 lua_setmetatable(L, -2);
1933
1934
1935 return 1;
1936}
1937
1938__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
1939{
1940 struct map_descriptor *desc;
1941 struct pattern *pat;
1942 struct sample smp;
1943
1944 MAY_LJMP(check_args(L, 2, "lookup"));
1945 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001946 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001947 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001948 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001949 }
1950 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001951 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001952 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001953 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 +01001954 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001955 }
1956
1957 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02001958 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001959 if (str)
1960 lua_pushstring(L, "");
1961 else
1962 lua_pushnil(L);
1963 return 1;
1964 }
1965
1966 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001967 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001968 return 1;
1969}
1970
1971__LJMP static int hlua_map_lookup(struct lua_State *L)
1972{
1973 return _hlua_map_lookup(L, 0);
1974}
1975
1976__LJMP static int hlua_map_slookup(struct lua_State *L)
1977{
1978 return _hlua_map_lookup(L, 1);
1979}
1980
1981/*
1982 *
1983 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001984 * Class Socket
1985 *
1986 *
1987 */
1988
1989__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
1990{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001991 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001992}
1993
1994/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001995 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001996 * received.
1997 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001998static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001999{
Willy Tarreau5321da92022-05-06 11:57:34 +02002000 struct hlua_csk_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002001 struct stconn *sc = appctx_sc(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002002
Willy Tarreau5321da92022-05-06 11:57:34 +02002003 if (ctx->die) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02002004 sc_shutw(sc);
2005 sc_shutr(sc);
Willy Tarreau5321da92022-05-06 11:57:34 +02002006 notification_wake(&ctx->wake_on_read);
2007 notification_wake(&ctx->wake_on_write);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002008 stream_shutdown(__sc_strm(sc), SF_ERR_KILLED);
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002009 }
2010
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002011 /* If we can't write, wakeup the pending write signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002012 if (channel_output_closed(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002013 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002014
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002015 /* If we can't read, wakeup the pending read signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002016 if (channel_input_closed(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002017 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002018
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002019 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002020 * to be notified whenever the connection completes.
2021 */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002022 if (sc_opposite(sc)->state < SC_ST_EST) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02002023 applet_need_more_data(appctx);
Willy Tarreaub23edc82022-05-24 16:49:03 +02002024 se_need_remote_conn(appctx->sedesc);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002025 applet_have_more_data(appctx);
Willy Tarreaud4da1962015-04-20 01:31:23 +02002026 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002027 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002028
2029 /* This function is called after the connect. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002030 ctx->connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002031
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002032 /* Wake the tasks which wants to write if the buffer have available space. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002033 if (channel_may_recv(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002034 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002035
2036 /* Wake the tasks which wants to read if the buffer contains data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002037 if (!channel_is_empty(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002038 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002039
2040 /* Some data were injected in the buffer, notify the stream
2041 * interface.
2042 */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002043 if (!channel_is_empty(sc_ic(sc)))
2044 sc_update(sc);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002045
2046 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01002047 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002048 */
Willy Tarreau5321da92022-05-06 11:57:34 +02002049 if (notification_registered(&ctx->wake_on_write))
Willy Tarreau4164eb92022-05-25 15:42:03 +02002050 applet_have_more_data(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002051}
2052
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002053static int hlua_socket_init(struct appctx *appctx)
2054{
2055 struct hlua_csk_ctx *ctx = appctx->svcctx;
2056 struct stream *s;
2057
2058 if (appctx_finalize_startup(appctx, socket_proxy, &BUF_NULL) == -1)
2059 goto error;
2060
2061 s = appctx_strm(appctx);
2062
Willy Tarreau4596fe22022-05-17 19:07:51 +02002063 /* Configure "right" stream connector. This stconn is used to connect
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002064 * and retrieve data from the server. The connection is initialized
2065 * with the "struct server".
2066 */
Willy Tarreau74568cf2022-05-27 09:03:30 +02002067 sc_set_state(s->scb, SC_ST_ASS);
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002068
2069 /* Force destination server. */
2070 s->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
2071 s->target = &socket_tcp->obj_type;
2072
2073 ctx->appctx = appctx;
2074 return 0;
2075
2076 error:
2077 return -1;
2078}
2079
Willy Tarreau87b09662015-04-03 00:22:06 +02002080/* This function is called when the "struct stream" is destroyed.
2081 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002082 * Wake all the pending signals.
2083 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002084static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002085{
Willy Tarreau5321da92022-05-06 11:57:34 +02002086 struct hlua_csk_ctx *ctx = appctx->svcctx;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002087 struct xref *peer;
2088
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002089 /* Remove my link in the original objects. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002090 peer = xref_get_peer_and_lock(&ctx->xref);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002091 if (peer)
Willy Tarreau5321da92022-05-06 11:57:34 +02002092 xref_disconnect(&ctx->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002093
2094 /* Wake all the task waiting for me. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002095 notification_wake(&ctx->wake_on_read);
2096 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002097}
2098
2099/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02002100 * uses this object. If the stream does not exists, just quit.
2101 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002102 * pending signal can rest in the read and write lists. destroy
2103 * it.
2104 */
2105__LJMP static int hlua_socket_gc(lua_State *L)
2106{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002107 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002108 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002109 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002110
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002111 MAY_LJMP(check_args(L, 1, "__gc"));
2112
2113 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002114 peer = xref_get_peer_and_lock(&socket->xref);
2115 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002116 return 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02002117
2118 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002119
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002120 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002121 ctx->die = 1;
2122 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002123
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002124 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002125 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002126 return 0;
2127}
2128
2129/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02002130 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002131 */
sada05ed3302018-05-11 11:48:18 -07002132__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002133{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002134 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002135 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002136 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002137 struct hlua *hlua;
2138
2139 /* Get hlua struct, or NULL if we execute from main lua state */
2140 hlua = hlua_gethlua(L);
2141 if (!hlua)
2142 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002143
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002144 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002145
2146 /* Check if we run on the same thread than the xreator thread.
2147 * We cannot access to the socket if the thread is different.
2148 */
2149 if (socket->tid != tid)
2150 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2151
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002152 peer = xref_get_peer_and_lock(&socket->xref);
2153 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002154 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01002155
2156 hlua->gc_count--;
Willy Tarreau5321da92022-05-06 11:57:34 +02002157 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002158
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002159 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002160 ctx->die = 1;
2161 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002162
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002163 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002164 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002165 return 0;
2166}
2167
sada05ed3302018-05-11 11:48:18 -07002168/* The close function calls close_helper.
2169 */
2170__LJMP static int hlua_socket_close(lua_State *L)
2171{
2172 MAY_LJMP(check_args(L, 1, "close"));
2173 return hlua_socket_close_helper(L);
2174}
2175
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002176/* This Lua function assumes that the stack contain three parameters.
2177 * 1 - USERDATA containing a struct socket
2178 * 2 - INTEGER with values of the macro defined below
2179 * If the integer is -1, we must read at most one line.
2180 * If the integer is -2, we ust read all the data until the
2181 * end of the stream.
2182 * If the integer is positive value, we must read a number of
2183 * bytes corresponding to this value.
2184 */
2185#define HLSR_READ_LINE (-1)
2186#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002187__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002188{
2189 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
2190 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002191 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002192 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002193 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002194 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002195 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02002196 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002197 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02002198 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002199 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002200 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01002201 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002202 struct stream *s;
2203 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002204 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002205
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002206 /* Get hlua struct, or NULL if we execute from main lua state */
2207 hlua = hlua_gethlua(L);
2208
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002209 /* Check if this lua stack is schedulable. */
2210 if (!hlua || !hlua->task)
2211 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
2212 "'frontend', 'backend' or 'task'"));
2213
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002214 /* Check if we run on the same thread than the xreator thread.
2215 * We cannot access to the socket if the thread is different.
2216 */
2217 if (socket->tid != tid)
2218 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2219
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002220 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002221 peer = xref_get_peer_and_lock(&socket->xref);
2222 if (!peer)
2223 goto no_peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002224
2225 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2226 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002227 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002228
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002229 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002230 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002231 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002232 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002233 if (nblk < 0) /* Connection close. */
2234 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002235 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002236 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002237
2238 /* remove final \r\n. */
2239 if (nblk == 1) {
2240 if (blk1[len1-1] == '\n') {
2241 len1--;
2242 skip_at_end++;
2243 if (blk1[len1-1] == '\r') {
2244 len1--;
2245 skip_at_end++;
2246 }
2247 }
2248 }
2249 else {
2250 if (blk2[len2-1] == '\n') {
2251 len2--;
2252 skip_at_end++;
2253 if (blk2[len2-1] == '\r') {
2254 len2--;
2255 skip_at_end++;
2256 }
2257 }
2258 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002259 }
2260
2261 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002262 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002263 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002264 if (nblk < 0) /* Connection close. */
2265 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002266 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002267 goto connection_empty;
2268 }
2269
2270 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002271 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002272 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002273 if (nblk < 0) /* Connection close. */
2274 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002275 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002276 goto connection_empty;
2277
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002278 missing_bytes = wanted - socket->b.n;
2279 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002280 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002281 len1 = missing_bytes;
2282 } if (nblk == 2 && len1 + len2 > missing_bytes)
2283 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002284 }
2285
2286 len = len1;
2287
2288 luaL_addlstring(&socket->b, blk1, len1);
2289 if (nblk == 2) {
2290 len += len2;
2291 luaL_addlstring(&socket->b, blk2, len2);
2292 }
2293
2294 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002295 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002296
2297 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002298 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002299
2300 /* If the pattern reclaim to read all the data
2301 * in the connection, got out.
2302 */
2303 if (wanted == HLSR_READ_ALL)
2304 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002305 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002306 goto connection_empty;
2307
2308 /* Return result. */
2309 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002310 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002311 return 1;
2312
2313connection_closed:
2314
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002315 xref_unlock(&socket->xref, peer);
2316
2317no_peer:
2318
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002319 /* If the buffer containds data. */
2320 if (socket->b.n > 0) {
2321 luaL_pushresult(&socket->b);
2322 return 1;
2323 }
2324 lua_pushnil(L);
2325 lua_pushstring(L, "connection closed.");
2326 return 2;
2327
2328connection_empty:
2329
Willy Tarreau5321da92022-05-06 11:57:34 +02002330 if (!notification_new(&hlua->com, &csk_ctx->wake_on_read, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002331 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002332 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002333 }
2334 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002335 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002336 return 0;
2337}
2338
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002339/* This Lua function gets two parameters. The first one can be string
2340 * or a number. If the string is "*l", the user requires one line. If
2341 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002342 * If the value is a number, the user require a number of bytes equal
2343 * to the value. The default value is "*l" (a line).
2344 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002345 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002346 * integer takes this values:
2347 * -1 : read a line
2348 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002349 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002350 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002351 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002352 * concatenated with the read data.
2353 */
2354__LJMP static int hlua_socket_receive(struct lua_State *L)
2355{
2356 int wanted = HLSR_READ_LINE;
2357 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002358 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002359 char *error;
2360 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002361 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002362
2363 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2364 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2365
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002366 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002367
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002368 /* Check if we run on the same thread than the xreator thread.
2369 * We cannot access to the socket if the thread is different.
2370 */
2371 if (socket->tid != tid)
2372 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2373
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002374 /* check for pattern. */
2375 if (lua_gettop(L) >= 2) {
2376 type = lua_type(L, 2);
2377 if (type == LUA_TSTRING) {
2378 pattern = lua_tostring(L, 2);
2379 if (strcmp(pattern, "*a") == 0)
2380 wanted = HLSR_READ_ALL;
2381 else if (strcmp(pattern, "*l") == 0)
2382 wanted = HLSR_READ_LINE;
2383 else {
2384 wanted = strtoll(pattern, &error, 10);
2385 if (*error != '\0')
2386 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2387 }
2388 }
2389 else if (type == LUA_TNUMBER) {
2390 wanted = lua_tointeger(L, 2);
2391 if (wanted < 0)
2392 WILL_LJMP(luaL_error(L, "Unsupported size."));
2393 }
2394 }
2395
2396 /* Set pattern. */
2397 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002398
2399 /* Check if we would replace the top by itself. */
2400 if (lua_gettop(L) != 2)
2401 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002402
Christopher Fauletc31b2002021-05-03 10:11:13 +02002403 /* Save index of the top of the stack because since buffers are used, it
2404 * may change
2405 */
2406 lastarg = lua_gettop(L);
2407
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002408 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002409 luaL_buffinit(L, &socket->b);
2410
2411 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002412 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002413 if (lua_type(L, 3) != LUA_TSTRING)
2414 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2415 pattern = lua_tolstring(L, 3, &len);
2416 luaL_addlstring(&socket->b, pattern, len);
2417 }
2418
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002419 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002420}
2421
2422/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002423 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002424 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002425static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002426{
2427 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002428 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002429 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002430 struct appctx *appctx;
2431 size_t buf_len;
2432 const char *buf;
2433 int len;
2434 int send_len;
2435 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002436 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002437 struct stream *s;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002438 struct stconn *sc;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002439
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002440 /* Get hlua struct, or NULL if we execute from main lua state */
2441 hlua = hlua_gethlua(L);
2442
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002443 /* Check if this lua stack is schedulable. */
2444 if (!hlua || !hlua->task)
2445 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2446 "'frontend', 'backend' or 'task'"));
2447
2448 /* Get object */
2449 socket = MAY_LJMP(hlua_checksocket(L, 1));
2450 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002451 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002452
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002453 /* Check if we run on the same thread than the xreator thread.
2454 * We cannot access to the socket if the thread is different.
2455 */
2456 if (socket->tid != tid)
2457 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2458
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002459 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002460 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002461 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002462 lua_pushinteger(L, -1);
2463 return 1;
2464 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002465
2466 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2467 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002468 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002469 s = __sc_strm(sc);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002470
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002471 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002472 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002473 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002474 lua_pushinteger(L, -1);
2475 return 1;
2476 }
2477
2478 /* Update the input buffer data. */
2479 buf += sent;
2480 send_len = buf_len - sent;
2481
2482 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002483 if (sent >= buf_len) {
2484 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002485 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002486 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002487
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002488 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002489 * the request buffer if its not required.
2490 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002491 if (s->req.buf.size == 0) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02002492 if (!sc_alloc_ibuf(sc, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002493 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002494 }
2495
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002496 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002497 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002498 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002499 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002500 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002501
2502 /* send data */
2503 if (len < send_len)
2504 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002505 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002506
2507 /* "Not enough space" (-1), "Buffer too little to contain
2508 * the data" (-2) are not expected because the available length
2509 * is tested.
2510 * Other unknown error are also not expected.
2511 */
2512 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002513 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002514 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002515
sada05ed3302018-05-11 11:48:18 -07002516 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002517 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002518 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002519 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002520 return 1;
2521 }
2522
2523 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002524 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002525
Christopher Fauletf8413cb2023-02-07 16:06:14 +01002526 sc_ep_reset_rex(s->scf);;
2527 sc_ep_reset_wex(s->scb);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002528
2529 /* Update length sent. */
2530 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002531 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002532
2533 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002534 if (sent + len >= buf_len) {
2535 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002536 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002537 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002538
2539hlua_socket_write_yield_return:
Willy Tarreau5321da92022-05-06 11:57:34 +02002540 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002541 xref_unlock(&socket->xref, peer);
2542 WILL_LJMP(luaL_error(L, "out of memory"));
2543 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002544 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002545 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002546 return 0;
2547}
2548
2549/* This function initiate the send of data. It just check the input
2550 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002551 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002552 * "hlua_socket_write_yield" that can yield.
2553 *
2554 * The Lua function gets between 3 and 4 parameters. The first one is
2555 * the associated object. The second is a string buffer. The third is
2556 * a facultative integer that represents where is the buffer position
2557 * of the start of the data that can send. The first byte is the
2558 * position "1". The default value is "1". The fourth argument is a
2559 * facultative integer that represents where is the buffer position
2560 * of the end of the data that can send. The default is the last byte.
2561 */
2562static int hlua_socket_send(struct lua_State *L)
2563{
2564 int i;
2565 int j;
2566 const char *buf;
2567 size_t buf_len;
2568
2569 /* Check number of arguments. */
2570 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2571 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2572
2573 /* Get the string. */
2574 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2575
2576 /* Get and check j. */
2577 if (lua_gettop(L) == 4) {
2578 j = MAY_LJMP(luaL_checkinteger(L, 4));
2579 if (j < 0)
2580 j = buf_len + j + 1;
2581 if (j > buf_len)
2582 j = buf_len + 1;
2583 lua_pop(L, 1);
2584 }
2585 else
2586 j = buf_len;
2587
2588 /* Get and check i. */
2589 if (lua_gettop(L) == 3) {
2590 i = MAY_LJMP(luaL_checkinteger(L, 3));
2591 if (i < 0)
2592 i = buf_len + i + 1;
2593 if (i > buf_len)
2594 i = buf_len + 1;
2595 lua_pop(L, 1);
2596 } else
2597 i = 1;
2598
2599 /* Check bth i and j. */
2600 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002601 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002602 return 1;
2603 }
2604 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002605 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002606 return 1;
2607 }
2608 if (i == 0)
2609 i = 1;
2610 if (j == 0)
2611 j = 1;
2612
2613 /* Pop the string. */
2614 lua_pop(L, 1);
2615
2616 /* Update the buffer length. */
2617 buf += i - 1;
2618 buf_len = j - i + 1;
2619 lua_pushlstring(L, buf, buf_len);
2620
2621 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002622 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002623
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002624 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002625}
2626
Willy Tarreau22b0a682015-06-17 19:43:49 +02002627#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Christopher Faulete6465b32021-10-22 15:36:08 +02002628__LJMP static inline int hlua_socket_info(struct lua_State *L, const struct sockaddr_storage *addr)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002629{
2630 static char buffer[SOCKET_INFO_MAX_LEN];
2631 int ret;
2632 int len;
2633 char *p;
2634
2635 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2636 if (ret <= 0) {
2637 lua_pushnil(L);
2638 return 1;
2639 }
2640
2641 if (ret == AF_UNIX) {
2642 lua_pushstring(L, buffer+1);
2643 return 1;
2644 }
2645 else if (ret == AF_INET6) {
2646 buffer[0] = '[';
2647 len = strlen(buffer);
2648 buffer[len] = ']';
2649 len++;
2650 buffer[len] = ':';
2651 len++;
2652 p = buffer;
2653 }
2654 else if (ret == AF_INET) {
2655 p = buffer + 1;
2656 len = strlen(p);
2657 p[len] = ':';
2658 len++;
2659 }
2660 else {
2661 lua_pushnil(L);
2662 return 1;
2663 }
2664
2665 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2666 lua_pushnil(L);
2667 return 1;
2668 }
2669
2670 lua_pushstring(L, p);
2671 return 1;
2672}
2673
2674/* Returns information about the peer of the connection. */
2675__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2676{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002677 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002678 struct xref *peer;
2679 struct appctx *appctx;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002680 struct stconn *sc;
Christopher Faulet16f16af2021-10-27 09:34:56 +02002681 const struct sockaddr_storage *dst;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002682 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002683
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002684 MAY_LJMP(check_args(L, 1, "getpeername"));
2685
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002686 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002687
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002688 /* Check if we run on the same thread than the xreator thread.
2689 * We cannot access to the socket if the thread is different.
2690 */
2691 if (socket->tid != tid)
2692 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2693
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002694 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002695 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002696 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002697 lua_pushnil(L);
2698 return 1;
2699 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002700
2701 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002702 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002703 dst = sc_dst(sc_opposite(sc));
Christopher Faulet16f16af2021-10-27 09:34:56 +02002704 if (!dst) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002705 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002706 lua_pushnil(L);
2707 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002708 }
2709
Christopher Faulet16f16af2021-10-27 09:34:56 +02002710 ret = MAY_LJMP(hlua_socket_info(L, dst));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002711 xref_unlock(&socket->xref, peer);
2712 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002713}
2714
2715/* Returns information about my connection side. */
2716static int hlua_socket_getsockname(struct lua_State *L)
2717{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002718 struct hlua_socket *socket;
2719 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002720 struct appctx *appctx;
2721 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002722 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002723 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002724
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002725 MAY_LJMP(check_args(L, 1, "getsockname"));
2726
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002727 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002728
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002729 /* Check if we run on the same thread than the xreator thread.
2730 * We cannot access to the socket if the thread is different.
2731 */
2732 if (socket->tid != tid)
2733 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2734
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002735 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002736 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002737 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002738 lua_pushnil(L);
2739 return 1;
2740 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002741
2742 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002743 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002744
Willy Tarreaufd9417b2022-05-18 16:23:22 +02002745 conn = sc_conn(s->scb);
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002746 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002747 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002748 lua_pushnil(L);
2749 return 1;
2750 }
2751
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002752 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002753 xref_unlock(&socket->xref, peer);
2754 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002755}
2756
2757/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002758static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002759 .obj_type = OBJ_TYPE_APPLET,
2760 .name = "<LUA_TCP>",
2761 .fct = hlua_socket_handler,
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002762 .init = hlua_socket_init,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002763 .release = hlua_socket_release,
2764};
2765
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002766__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002767{
2768 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002769 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002770 struct xref *peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002771 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002772 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002773 struct stream *s;
2774
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002775 /* Get hlua struct, or NULL if we execute from main lua state */
2776 hlua = hlua_gethlua(L);
2777 if (!hlua)
2778 return 0;
2779
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002780 /* Check if we run on the same thread than the xreator thread.
2781 * We cannot access to the socket if the thread is different.
2782 */
2783 if (socket->tid != tid)
2784 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2785
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002786 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002787 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002788 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002789 lua_pushnil(L);
2790 lua_pushstring(L, "Can't connect");
2791 return 2;
2792 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002793
2794 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2795 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002796 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002797
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002798 /* Check if we run on the same thread than the xreator thread.
2799 * We cannot access to the socket if the thread is different.
2800 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002801 if (socket->tid != tid) {
2802 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002803 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002804 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002805
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002806 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002807 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002808 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002809 lua_pushnil(L);
2810 lua_pushstring(L, "Can't connect");
2811 return 2;
2812 }
2813
Willy Tarreau8e7c6e62022-05-18 17:58:02 +02002814 appctx = __sc_appctx(s->scf);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002815
2816 /* Check for connection established. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002817 if (csk_ctx->connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002818 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002819 lua_pushinteger(L, 1);
2820 return 1;
2821 }
2822
Willy Tarreau5321da92022-05-06 11:57:34 +02002823 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002824 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002825 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002826 }
2827 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002828 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002829 return 0;
2830}
2831
2832/* This function fail or initite the connection. */
2833__LJMP static int hlua_socket_connect(struct lua_State *L)
2834{
2835 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002836 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002837 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002838 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002839 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002840 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002841 int low, high;
2842 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002843 struct xref *peer;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002844 struct stconn *sc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002845 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002846
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002847 if (lua_gettop(L) < 2)
2848 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002849
2850 /* Get args. */
2851 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002852
2853 /* Check if we run on the same thread than the xreator thread.
2854 * We cannot access to the socket if the thread is different.
2855 */
2856 if (socket->tid != tid)
2857 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2858
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002859 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002860 if (lua_gettop(L) >= 3) {
2861 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002862 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002863
Tim Duesterhus6edab862018-01-06 19:04:45 +01002864 /* Force the ip to end with a colon, to support IPv6 addresses
2865 * that are not enclosed within square brackets.
2866 */
2867 if (port > 0) {
2868 luaL_buffinit(L, &b);
2869 luaL_addstring(&b, ip);
2870 luaL_addchar(&b, ':');
2871 luaL_pushresult(&b);
2872 ip = lua_tolstring(L, lua_gettop(L), NULL);
2873 }
2874 }
2875
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002876 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002877 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002878 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002879 lua_pushnil(L);
2880 return 1;
2881 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002882
2883 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002884 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 +02002885 if (!addr) {
2886 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002887 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002888 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002889
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002890 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002891 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002892 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002893 if (port == -1) {
2894 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002895 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002896 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002897 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2898 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002899 if (port == -1) {
2900 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002901 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002902 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002903 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002904 }
2905 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002906
Willy Tarreau5321da92022-05-06 11:57:34 +02002907 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2908 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002909 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002910 s = __sc_strm(sc);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002911
Willy Tarreau3e7be362022-05-27 10:35:27 +02002912 if (!sockaddr_alloc(&sc_opposite(sc)->dst, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002913 xref_unlock(&socket->xref, peer);
2914 WILL_LJMP(luaL_error(L, "connect: internal error"));
2915 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002916
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002917 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002918 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002919 if (!hlua)
2920 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002921
2922 /* inform the stream that we want to be notified whenever the
2923 * connection completes.
2924 */
Willy Tarreau90e8b452022-05-25 18:21:43 +02002925 applet_need_more_data(appctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002926 applet_have_more_data(appctx);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002927 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002928
Willy Tarreauf31af932020-01-14 09:59:38 +01002929 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002930
Willy Tarreau5321da92022-05-06 11:57:34 +02002931 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002932 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002933 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002934 }
2935 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002936
2937 task_wakeup(s->task, TASK_WOKEN_INIT);
2938 /* Return yield waiting for connection. */
2939
Willy Tarreau9635e032018-10-16 17:52:55 +02002940 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002941
2942 return 0;
2943}
2944
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002945#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002946__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
2947{
2948 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002949 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002950 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002951
2952 MAY_LJMP(check_args(L, 3, "connect_ssl"));
2953 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002954
2955 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002956 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002957 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002958 lua_pushnil(L);
2959 return 1;
2960 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002961
Willy Tarreau0698c802022-05-11 14:09:57 +02002962 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002963
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002964 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002965 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002966 return MAY_LJMP(hlua_socket_connect(L));
2967}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002968#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002969
2970__LJMP static int hlua_socket_setoption(struct lua_State *L)
2971{
2972 return 0;
2973}
2974
2975__LJMP static int hlua_socket_settimeout(struct lua_State *L)
2976{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002977 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002978 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02002979 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002980 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002981 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002982
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002983 MAY_LJMP(check_args(L, 2, "settimeout"));
2984
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002985 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02002986
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002987 /* convert the timeout to millis */
2988 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002989
Thierry Fournier17a921b2018-03-08 09:59:02 +01002990 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02002991 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01002992 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
2993
Mark Lakes56cc1252018-03-27 09:48:06 +02002994 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002995 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02002996
2997 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002998 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002999 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02003000
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003001 /* Check if we run on the same thread than the xreator thread.
3002 * We cannot access to the socket if the thread is different.
3003 */
3004 if (socket->tid != tid)
3005 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
3006
Mark Lakes56cc1252018-03-27 09:48:06 +02003007 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003008 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003009 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003010 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
3011 WILL_LJMP(lua_error(L));
3012 return 0;
3013 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003014
Willy Tarreau0698c802022-05-11 14:09:57 +02003015 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003016
Cyril Bonté7bb63452018-08-17 23:51:02 +02003017 s->sess->fe->timeout.connect = tmout;
Christopher Faulet5aaacfb2023-02-15 08:13:33 +01003018 s->scf->ioto = tmout;
3019 s->scb->ioto = tmout;
Christopher Fauletf8413cb2023-02-07 16:06:14 +01003020 sc_ep_set_rex(s->scf, tmout);
3021 sc_ep_set_wex(s->scf, tmout);
3022 sc_ep_set_rex(s->scb, tmout);
3023 sc_ep_set_wex(s->scb, tmout);
Cyril Bonté7bb63452018-08-17 23:51:02 +02003024
3025 s->task->expire = tick_add_ifset(now_ms, tmout);
3026 task_queue(s->task);
3027
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003028 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003029
Thierry Fourniere9636f12018-03-08 09:54:32 +01003030 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01003031 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003032}
3033
3034__LJMP static int hlua_socket_new(lua_State *L)
3035{
3036 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02003037 struct hlua_csk_ctx *ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003038 struct appctx *appctx;
3039
3040 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003041 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003042 hlua_pusherror(L, "socket: full stack");
3043 goto out_fail_conf;
3044 }
3045
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003046 /* Create the object: obj[0] = userdata. */
3047 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003048 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003049 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003050 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003051 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003052
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003053 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01003054 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01003055 hlua_pusherror(L, "socket: uninitialized pools.");
3056 goto out_fail_conf;
3057 }
3058
Willy Tarreau87b09662015-04-03 00:22:06 +02003059 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003060 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
3061 lua_setmetatable(L, -2);
3062
Willy Tarreaud420a972015-04-06 00:39:18 +02003063 /* Create the applet context */
Christopher Faulet6095d572022-05-16 17:09:48 +02003064 appctx = appctx_new_here(&update_applet, NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003065 if (!appctx) {
3066 hlua_pusherror(L, "socket: out of memory");
Christopher Fauleta9e8b392022-03-23 11:01:09 +01003067 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003068 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003069 ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
3070 ctx->connected = 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02003071 ctx->die = 0;
3072 LIST_INIT(&ctx->wake_on_write);
3073 LIST_INIT(&ctx->wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02003074
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003075 if (appctx_init(appctx) == -1) {
3076 hlua_pusherror(L, "socket: fail to init applet.");
Christopher Faulet13a35e52021-12-20 15:34:16 +01003077 goto out_fail_appctx;
3078 }
3079
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003080 /* Initialise cross reference between stream and Lua socket object. */
Willy Tarreau5321da92022-05-06 11:57:34 +02003081 xref_create(&socket->xref, &ctx->xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003082 return 1;
3083
Christopher Faulet13a35e52021-12-20 15:34:16 +01003084 out_fail_appctx:
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003085 appctx_free_on_early_error(appctx);
Willy Tarreaud420a972015-04-06 00:39:18 +02003086 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003087 WILL_LJMP(lua_error(L));
3088 return 0;
3089}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01003090
3091/*
3092 *
3093 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003094 * Class Channel
3095 *
3096 *
3097 */
3098
3099/* Returns the struct hlua_channel join to the class channel in the
3100 * stack entry "ud" or throws an argument error.
3101 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003102__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003103{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003104 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003105}
3106
Willy Tarreau47860ed2015-03-10 14:07:50 +01003107/* Pushes the channel onto the top of the stack. If the stask does not have a
3108 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003109 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01003110static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003111{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003112 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003113 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003114 return 0;
3115
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003116 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003117 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003118 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003119
3120 /* Pop a class sesison metatable and affect it to the userdata. */
3121 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
3122 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003123 return 1;
3124}
3125
Christopher Faulet9f55a502020-02-25 15:21:02 +01003126/* Helper function returning a filter attached to a channel at the position <ud>
3127 * in the stack, filling the current offset and length of the filter. If no
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05003128 * filter is attached, NULL is returned and <offset> and <len> are not
Christopher Faulet9f55a502020-02-25 15:21:02 +01003129 * initialized.
3130 */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003131static struct filter *hlua_channel_filter(lua_State *L, int ud, struct channel *chn, size_t *offset, size_t *len)
Christopher Faulet9f55a502020-02-25 15:21:02 +01003132{
3133 struct filter *filter = NULL;
3134
3135 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
3136 struct hlua_flt_ctx *flt_ctx;
3137
3138 filter = lua_touserdata (L, -1);
3139 flt_ctx = filter->ctx;
3140 if (hlua_filter_from_payload(filter)) {
3141 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
3142 *len = flt_ctx->cur_len[CHN_IDX(chn)];
3143 }
3144 }
3145
3146 lua_pop(L, 1);
3147 return filter;
3148}
3149
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003150/* Copies <len> bytes of data present in the channel's buffer, starting at the
3151* offset <offset>, and put it in a LUA string variable. It is the caller
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003152* responsibility to ensure <len> and <offset> are valid. It always return the
3153* length of the built string. <len> may be 0, in this case, an empty string is
3154* created and 0 is returned.
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003155*/
3156static inline int _hlua_channel_dup(struct channel *chn, lua_State *L, size_t offset, size_t len)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003157{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003158 size_t block1, block2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003159 luaL_Buffer b;
3160
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003161 block1 = len;
3162 if (block1 > b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset)))
3163 block1 = b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset));
3164 block2 = len - block1;
3165
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003166 luaL_buffinit(L, &b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003167 luaL_addlstring(&b, b_peek(&chn->buf, offset), block1);
3168 if (block2)
3169 luaL_addlstring(&b, b_orig(&chn->buf), block2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003170 luaL_pushresult(&b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003171 return len;
3172}
3173
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003174/* Inserts the string <str> to the channel's buffer at the offset <offset>. This
3175 * function returns -1 if data cannot be copied. Otherwise, it returns the
3176 * number of bytes copied.
3177 */
3178static int _hlua_channel_insert(struct channel *chn, lua_State *L, struct ist str, size_t offset)
3179{
3180 int ret = 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003181
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003182 /* Nothing to do, just return */
3183 if (unlikely(istlen(str) == 0))
3184 goto end;
3185
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003186 if (istlen(str) > c_room(chn)) {
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003187 ret = -1;
3188 goto end;
3189 }
3190 ret = b_insert_blk(&chn->buf, offset, istptr(str), istlen(str));
3191
3192 end:
3193 return ret;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003194}
3195
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003196/* Removes <len> bytes of data at the absolute position <offset>.
3197 */
3198static void _hlua_channel_delete(struct channel *chn, size_t offset, size_t len)
3199{
3200 size_t end = offset + len;
3201
3202 if (b_peek(&chn->buf, end) != b_tail(&chn->buf))
3203 b_move(&chn->buf, b_peek_ofs(&chn->buf, end),
3204 b_data(&chn->buf) - end, -len);
3205 b_sub(&chn->buf, len);
3206}
3207
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003208/* Copies input data in the channel's buffer. It is possible to set a specific
3209 * offset (0 by default) and a length (all remaining input data starting for the
3210 * offset by default). If there is not enough input data and more data can be
3211 * received, this function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003212 *
3213 * From an action, All input data are considered. For a filter, the offset and
3214 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003215 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003216__LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003217{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003218 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003219 struct filter *filter;
3220 size_t input, output;
3221 int offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003222
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003223 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003224
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003225 output = co_data(chn);
3226 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003227
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003228 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3229 if (filter && !hlua_filter_from_payload(filter))
3230 WILL_LJMP(lua_error(L));
3231
3232 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003233 if (lua_gettop(L) > 1) {
3234 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3235 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003236 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003237 offset += output;
3238 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003239 lua_pushfstring(L, "offset out of range.");
3240 WILL_LJMP(lua_error(L));
3241 }
3242 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003243 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003244 if (lua_gettop(L) == 3) {
3245 len = MAY_LJMP(luaL_checkinteger(L, 3));
3246 if (!len)
3247 goto dup;
3248 if (len == -1)
3249 len = global.tune.bufsize;
3250 if (len < 0) {
3251 lua_pushfstring(L, "length out of range.");
3252 WILL_LJMP(lua_error(L));
3253 }
3254 }
3255
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003256 /* Wait for more data if possible if no length was specified and there
3257 * is no data or not enough data was received.
3258 */
3259 if (!len || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003260 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3261 /* Yield waiting for more data, as requested */
3262 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_data_yield, TICK_ETERNITY, 0));
3263 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003264
3265 /* Return 'nil' if there is no data and the channel can't receive more data */
3266 if (!len) {
3267 lua_pushnil(L);
3268 return -1;
3269 }
3270
3271 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003272 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003273 }
3274
3275 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003276 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003277 return 1;
3278}
3279
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003280/* Copies the first line (including the trailing LF) of input data in the
3281 * channel's buffer. It is possible to set a specific offset (0 by default) and
3282 * a length (all remaining input data starting for the offset by default). If
3283 * there is not enough input data and more data can be received, the function
3284 * yields. If a length is explicitly specified, no more data are
3285 * copied. Otherwise, if no LF is found and more data can be received, this
3286 * function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003287 *
3288 * From an action, All input data are considered. For a filter, the offset and
3289 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003290 */
3291__LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003292{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003293 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003294 struct filter *filter;
3295 size_t l, input, output;
3296 int offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003297
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003298 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003299 output = co_data(chn);
3300 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003301
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003302 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3303 if (filter && !hlua_filter_from_payload(filter))
3304 WILL_LJMP(lua_error(L));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003305
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003306 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003307 if (lua_gettop(L) > 1) {
3308 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3309 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003310 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003311 offset += output;
3312 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003313 lua_pushfstring(L, "offset out of range.");
3314 WILL_LJMP(lua_error(L));
3315 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003316 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003317
3318 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003319 if (lua_gettop(L) == 3) {
3320 len = MAY_LJMP(luaL_checkinteger(L, 3));
3321 if (!len)
3322 goto dup;
3323 if (len == -1)
3324 len = global.tune.bufsize;
3325 if (len < 0) {
3326 lua_pushfstring(L, "length out of range.");
3327 WILL_LJMP(lua_error(L));
3328 }
3329 }
3330
3331 for (l = 0; l < len; l++) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003332 if (l + offset >= output + input)
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003333 break;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003334 if (*(b_peek(&chn->buf, offset + l)) == '\n') {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003335 len = l+1;
3336 goto dup;
3337 }
3338 }
3339
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003340 /* Wait for more data if possible if no line is found and no length was
3341 * specified or not enough data was received.
3342 */
3343 if (lua_gettop(L) != 3 || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003344 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3345 /* Yield waiting for more data */
3346 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_line_yield, TICK_ETERNITY, 0));
3347 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003348
3349 /* Return 'nil' if there is no data and the channel can't receive more data */
3350 if (!len) {
3351 lua_pushnil(L);
3352 return -1;
3353 }
3354
3355 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003356 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003357 }
3358
3359 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003360 _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003361 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003362}
3363
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003364/* [ DEPRECATED ]
3365 *
3366 * Duplicate all input data foud in the channel's buffer. The data are not
3367 * removed from the buffer. This function relies on _hlua_channel_dup().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003368 *
3369 * From an action, All input data are considered. For a filter, the offset and
3370 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003371 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003372__LJMP static int hlua_channel_dup(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003373{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003374 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003375 struct filter *filter;
3376 size_t offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003377
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003378 MAY_LJMP(check_args(L, 1, "dup"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003379 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003380 if (IS_HTX_STRM(chn_strm(chn))) {
3381 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3382 WILL_LJMP(lua_error(L));
3383 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003384
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003385 offset = co_data(chn);
3386 len = ci_data(chn);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003387
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003388 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3389 if (filter && !hlua_filter_from_payload(filter))
3390 WILL_LJMP(lua_error(L));
3391
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003392 if (!ci_data(chn) && channel_input_closed(chn)) {
3393 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003394 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003395 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003396
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003397 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003398 return 1;
3399}
3400
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003401/* [ DEPRECATED ]
3402 *
3403 * Get all input data foud in the channel's buffer. The data are removed from
3404 * the buffer after the copy. This function relies on _hlua_channel_dup() and
3405 * _hlua_channel_delete().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003406 *
3407 * From an action, All input data are considered. For a filter, the offset and
3408 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003409 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003410__LJMP static int hlua_channel_get(lua_State *L)
3411{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003412 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003413 struct filter *filter;
3414 size_t offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003415 int ret;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003416
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003417 MAY_LJMP(check_args(L, 1, "get"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003418 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3419 if (IS_HTX_STRM(chn_strm(chn))) {
3420 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3421 WILL_LJMP(lua_error(L));
3422 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003423
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003424 offset = co_data(chn);
3425 len = ci_data(chn);
3426
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003427 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3428 if (filter && !hlua_filter_from_payload(filter))
3429 WILL_LJMP(lua_error(L));
3430
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003431 if (!ci_data(chn) && channel_input_closed(chn)) {
3432 lua_pushnil(L);
3433 return 1;
3434 }
3435
3436 ret = _hlua_channel_dup(chn, L, offset, len);
3437 _hlua_channel_delete(chn, offset, ret);
3438 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003439}
3440
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003441/* This functions consumes and returns one line. If the channel is closed,
3442 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003443 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003444 * value.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003445 *
3446 * From an action, All input data are considered. For a filter, the offset and
3447 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003448 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003449__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003450{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003451 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003452 struct filter *filter;
3453 size_t l, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003454 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003455
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003456 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003457
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003458 offset = co_data(chn);
3459 len = ci_data(chn);
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003460
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003461 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3462 if (filter && !hlua_filter_from_payload(filter))
3463 WILL_LJMP(lua_error(L));
3464
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003465 if (!ci_data(chn) && channel_input_closed(chn)) {
3466 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003467 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003468 }
3469
3470 for (l = 0; l < len; l++) {
3471 if (*(b_peek(&chn->buf, offset+l)) == '\n') {
3472 len = l+1;
3473 goto dup;
3474 }
3475 }
3476
3477 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3478 /* Yield waiting for more data */
3479 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
3480 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003481
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003482 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003483 ret = _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003484 _hlua_channel_delete(chn, offset, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003485 return 1;
3486}
3487
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003488/* [ DEPRECATED ]
3489 *
3490 * Check arguments for the function "hlua_channel_getline_yield".
3491 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003492__LJMP static int hlua_channel_getline(lua_State *L)
3493{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003494 struct channel *chn;
3495
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003496 MAY_LJMP(check_args(L, 1, "getline"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003497 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3498 if (IS_HTX_STRM(chn_strm(chn))) {
3499 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3500 WILL_LJMP(lua_error(L));
3501 }
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003502 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3503}
3504
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003505/* Retrieves a given amount of input data at the given offset. By default all
3506 * available input data are returned. The offset may be negactive to start from
3507 * the end of input data. The length may be -1 to set it to the maximum buffer
3508 * size.
3509 */
3510__LJMP static int hlua_channel_get_data(lua_State *L)
3511{
3512 struct channel *chn;
3513
3514 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3515 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
3516 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3517 if (IS_HTX_STRM(chn_strm(chn))) {
3518 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3519 WILL_LJMP(lua_error(L));
3520 }
3521 return MAY_LJMP(hlua_channel_get_data_yield(L, 0, 0));
3522}
3523
3524/* Retrieves a given amount of input data at the given offset. By default all
3525 * available input data are returned. The offset may be negactive to start from
3526 * the end of input data. The length may be -1 to set it to the maximum buffer
3527 * size.
3528 */
3529__LJMP static int hlua_channel_get_line(lua_State *L)
3530{
3531 struct channel *chn;
3532
3533 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3534 WILL_LJMP(luaL_error(L, "'line' expects at most 2 arguments"));
3535 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3536 if (IS_HTX_STRM(chn_strm(chn))) {
3537 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3538 WILL_LJMP(lua_error(L));
3539 }
3540 return MAY_LJMP(hlua_channel_get_line_yield(L, 0, 0));
3541}
3542
3543/* Appends a string into the input side of channel. It returns the length of the
3544 * written string, or -1 if the channel is closed or if the buffer size is too
3545 * little for the data. 0 may be returned if nothing is copied. This function
3546 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003547 *
3548 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003549 */
Christopher Faulet23976d92021-08-06 09:59:49 +02003550__LJMP static int hlua_channel_append(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003551{
Christopher Faulet23976d92021-08-06 09:59:49 +02003552 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003553 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003554 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003555 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003556 int ret;
Christopher Faulet23976d92021-08-06 09:59:49 +02003557
3558 MAY_LJMP(check_args(L, 2, "append"));
3559 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003560 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003561 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003562 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003563 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003564 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003565
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003566 offset = co_data(chn);
3567 len = ci_data(chn);
3568
3569 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3570 if (filter && !hlua_filter_from_payload(filter))
3571 WILL_LJMP(lua_error(L));
3572
3573 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3574 if (ret > 0 && filter) {
3575 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3576
3577 flt_update_offsets(filter, chn, ret);
3578 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3579 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003580 lua_pushinteger(L, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003581 return 1;
3582}
3583
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003584/* Prepends a string into the input side of channel. It returns the length of the
3585 * written string, or -1 if the channel is closed or if the buffer size is too
3586 * little for the data. 0 may be returned if nothing is copied. This function
3587 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003588 *
3589 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003590 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003591__LJMP static int hlua_channel_prepend(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003592{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003593 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003594 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003595 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003596 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003597 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003598
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003599 MAY_LJMP(check_args(L, 2, "prepend"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003600 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003601 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3602 if (IS_HTX_STRM(chn_strm(chn))) {
3603 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3604 WILL_LJMP(lua_error(L));
3605 }
3606
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003607 offset = co_data(chn);
3608 len = ci_data(chn);
3609
3610 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3611 if (filter && !hlua_filter_from_payload(filter))
3612 WILL_LJMP(lua_error(L));
3613
3614 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3615 if (ret > 0 && filter) {
3616 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3617
3618 flt_update_offsets(filter, chn, ret);
3619 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3620 }
3621
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003622 lua_pushinteger(L, ret);
3623 return 1;
3624}
3625
3626/* Inserts a given amount of input data at the given offset by a string
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003627 * content. By default the string is appended in front of input data. It
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003628 * returns the length of the written string, or -1 if the channel is closed or
3629 * if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003630 *
3631 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003632 */
3633__LJMP static int hlua_channel_insert_data(lua_State *L)
3634{
3635 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003636 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003637 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003638 size_t sz, input, output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003639 int ret, offset;
3640
3641 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
3642 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
3643 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3644 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003645
3646 output = co_data(chn);
3647 input = ci_data(chn);
3648
3649 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3650 if (filter && !hlua_filter_from_payload(filter))
3651 WILL_LJMP(lua_error(L));
3652
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003653 offset = output;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003654 if (lua_gettop(L) > 2) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003655 offset = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003656 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003657 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003658 offset += output;
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003659 if (offset > output + input) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003660 lua_pushfstring(L, "offset out of range.");
3661 WILL_LJMP(lua_error(L));
3662 }
3663 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003664 if (IS_HTX_STRM(chn_strm(chn))) {
3665 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3666 WILL_LJMP(lua_error(L));
3667 }
3668
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003669 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3670 if (ret > 0 && filter) {
3671 struct hlua_flt_ctx *flt_ctx = filter->ctx;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003672
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003673 flt_update_offsets(filter, chn, ret);
3674 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003675 }
3676
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003677 lua_pushinteger(L, ret);
3678 return 1;
3679}
3680/* Replaces a given amount of input data at the given offset by a string
3681 * content. By default all remaining data are removed (offset = 0 and len =
3682 * -1). It returns the length of the written string, or -1 if the channel is
3683 * closed or if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003684 *
3685 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003686 */
3687__LJMP static int hlua_channel_set_data(lua_State *L)
3688{
3689 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003690 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003691 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003692 size_t sz, input, output;
3693 int ret, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003694
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003695 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
3696 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
3697 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3698 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003699
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003700 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003701 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003702 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003703 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003704
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003705 output = co_data(chn);
3706 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003707
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003708 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3709 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003710 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003711
3712 offset = output;
3713 if (lua_gettop(L) > 2) {
3714 offset = MAY_LJMP(luaL_checkinteger(L, 3));
3715 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003716 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003717 offset += output;
3718 if (offset < output || offset > input + output) {
3719 lua_pushfstring(L, "offset out of range.");
3720 WILL_LJMP(lua_error(L));
3721 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003722 }
3723
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003724 len = output + input - offset;
3725 if (lua_gettop(L) == 4) {
3726 len = MAY_LJMP(luaL_checkinteger(L, 4));
3727 if (!len)
3728 goto set;
3729 if (len == -1)
3730 len = output + input - offset;
3731 if (len < 0 || offset + len > output + input) {
3732 lua_pushfstring(L, "length out of range.");
3733 WILL_LJMP(lua_error(L));
3734 }
3735 }
3736
3737 set:
Christopher Faulet23976d92021-08-06 09:59:49 +02003738 /* Be sure we can copied the string once input data will be removed. */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003739 if (sz > c_room(chn) + len)
Christopher Faulet23976d92021-08-06 09:59:49 +02003740 lua_pushinteger(L, -1);
3741 else {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003742 _hlua_channel_delete(chn, offset, len);
3743 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3744 if (filter) {
3745 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3746
3747 len -= (ret > 0 ? ret : 0);
3748 flt_update_offsets(filter, chn, -len);
3749 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3750 }
3751
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003752 lua_pushinteger(L, ret);
Christopher Faulet23976d92021-08-06 09:59:49 +02003753 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003754 return 1;
3755}
3756
3757/* Removes a given amount of input data at the given offset. By default all
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003758 * input data are removed (offset = 0 and len = -1). It returns the amount of
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003759 * the removed data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003760 *
3761 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003762 */
3763__LJMP static int hlua_channel_del_data(lua_State *L)
3764{
3765 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003766 struct filter *filter;
3767 size_t input, output;
3768 int offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003769
3770 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3771 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
3772 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003773
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003774 if (IS_HTX_STRM(chn_strm(chn))) {
3775 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3776 WILL_LJMP(lua_error(L));
3777 }
3778
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003779 output = co_data(chn);
3780 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003781
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003782 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3783 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003784 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003785
3786 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00003787 if (lua_gettop(L) > 1) {
3788 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003789 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003790 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003791 offset += output;
3792 if (offset < output || offset > input + output) {
3793 lua_pushfstring(L, "offset out of range.");
3794 WILL_LJMP(lua_error(L));
3795 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003796 }
3797
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003798 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00003799 if (lua_gettop(L) == 3) {
3800 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003801 if (!len)
3802 goto end;
3803 if (len == -1)
3804 len = output + input - offset;
3805 if (len < 0 || offset + len > output + input) {
3806 lua_pushfstring(L, "length out of range.");
3807 WILL_LJMP(lua_error(L));
3808 }
3809 }
3810
3811 _hlua_channel_delete(chn, offset, len);
3812 if (filter) {
3813 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3814
3815 flt_update_offsets(filter, chn, -len);
3816 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3817 }
3818
3819 end:
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003820 lua_pushinteger(L, len);
Christopher Faulet23976d92021-08-06 09:59:49 +02003821 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003822}
3823
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003824/* Append data in the output side of the buffer. This data is immediately
3825 * sent. The function returns the amount of data written. If the buffer
3826 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003827 * if the channel is closed.
3828 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003829__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003830{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003831 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003832 struct filter *filter;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003833 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003834 size_t offset, len, sz;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003835 int l, ret;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003836 struct hlua *hlua;
3837
3838 /* Get hlua struct, or NULL if we execute from main lua state */
3839 hlua = hlua_gethlua(L);
3840 if (!hlua) {
3841 lua_pushnil(L);
3842 return 1;
3843 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003844
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003845 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3846 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3847 l = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003848
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003849 offset = co_data(chn);
3850 len = ci_data(chn);
3851
3852 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3853 if (filter && !hlua_filter_from_payload(filter))
3854 WILL_LJMP(lua_error(L));
3855
3856
Willy Tarreau47860ed2015-03-10 14:07:50 +01003857 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003858 lua_pushinteger(L, -1);
3859 return 1;
3860 }
3861
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003862 len = c_room(chn);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003863 if (len > sz -l) {
3864 if (filter) {
3865 lua_pushinteger(L, -1);
3866 return 1;
3867 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003868 len = sz - l;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003869 }
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003870
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003871 ret = _hlua_channel_insert(chn, L, ist2(str, len), offset);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003872 if (ret == -1) {
3873 lua_pop(L, 1);
3874 lua_pushinteger(L, -1);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003875 return 1;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003876 }
3877 if (ret) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003878 if (filter) {
3879 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3880
3881
3882 flt_update_offsets(filter, chn, ret);
3883 FLT_OFF(filter, chn) += ret;
3884 flt_ctx->cur_off[CHN_IDX(chn)] += ret;
3885 }
3886 else
3887 c_adv(chn, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003888
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003889 l += ret;
3890 lua_pop(L, 1);
3891 lua_pushinteger(L, l);
3892 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003893
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003894 if (l < sz) {
3895 /* Yield only if the channel's output is not empty.
3896 * Otherwise it means we cannot add more data. */
3897 if (co_data(chn) == 0 || HLUA_CANT_YIELD(hlua_gethlua(L)))
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003898 return 1;
3899
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003900 /* If we are waiting for space in the response buffer, we
3901 * must set the flag WAKERESWR. This flag required the task
3902 * wake up if any activity is detected on the response buffer.
3903 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003904 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003905 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003906 else
3907 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003908 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003909 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003910
3911 return 1;
3912}
3913
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003914/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003915 * yield the LUA process, and resume it without checking the
3916 * input arguments.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003917 *
3918 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003919 */
3920__LJMP static int hlua_channel_send(lua_State *L)
3921{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003922 struct channel *chn;
3923
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003924 MAY_LJMP(check_args(L, 2, "send"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003925 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3926 if (IS_HTX_STRM(chn_strm(chn))) {
3927 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3928 WILL_LJMP(lua_error(L));
3929 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003930 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003931 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003932}
3933
3934/* This function forward and amount of butes. The data pass from
3935 * the input side of the buffer to the output side, and can be
3936 * forwarded. This function never fails.
3937 *
3938 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003939 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003940 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003941__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003942{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003943 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003944 struct filter *filter;
3945 size_t offset, len, fwd;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003946 int l, max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003947 struct hlua *hlua;
3948
3949 /* Get hlua struct, or NULL if we execute from main lua state */
3950 hlua = hlua_gethlua(L);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003951 if (!hlua) {
3952 lua_pushnil(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003953 return 1;
Thierry Fournier77016da2020-08-15 14:35:51 +02003954 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003955
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003956 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003957 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003958 l = MAY_LJMP(luaL_checkinteger(L, -1));
3959
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003960 offset = co_data(chn);
3961 len = ci_data(chn);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003962
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003963 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3964 if (filter && !hlua_filter_from_payload(filter))
3965 WILL_LJMP(lua_error(L));
3966
3967 max = fwd - l;
3968 if (max > len)
3969 max = len;
3970
3971 if (filter) {
3972 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3973
3974 FLT_OFF(filter, chn) += max;
3975 flt_ctx->cur_off[CHN_IDX(chn)] += max;
3976 flt_ctx->cur_len[CHN_IDX(chn)] -= max;
3977 }
3978 else
3979 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003980
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003981 l += max;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003982 lua_pop(L, 1);
3983 lua_pushinteger(L, l);
3984
3985 /* Check if it miss bytes to forward. */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003986 if (l < fwd) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003987 /* The the input channel or the output channel are closed, we
3988 * must return the amount of data forwarded.
3989 */
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003990 if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L)))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003991 return 1;
3992
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003993 /* If we are waiting for space data in the response buffer, we
3994 * must set the flag WAKERESWR. This flag required the task
3995 * wake up if any activity is detected on the response buffer.
3996 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003997 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003998 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003999 else
4000 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004001
Ilya Shipitsin4a689da2022-10-29 09:34:32 +05004002 /* Otherwise, we can yield waiting for new data in the input side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02004003 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004004 }
4005
4006 return 1;
4007}
4008
4009/* Just check the input and prepare the stack for the previous
4010 * function "hlua_channel_forward_yield"
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004011 *
4012 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004013 */
4014__LJMP static int hlua_channel_forward(lua_State *L)
4015{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004016 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004017
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004018 MAY_LJMP(check_args(L, 2, "forward"));
4019 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4020 if (IS_HTX_STRM(chn_strm(chn))) {
4021 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
4022 WILL_LJMP(lua_error(L));
4023 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004024 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004025 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004026}
4027
4028/* Just returns the number of bytes available in the input
4029 * side of the buffer. This function never fails.
4030 */
4031__LJMP static int hlua_channel_get_in_len(lua_State *L)
4032{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004033 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004034 struct filter *filter;
4035 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004036
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004037 MAY_LJMP(check_args(L, 1, "input"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004038 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004039
4040 output = co_data(chn);
4041 input = ci_data(chn);
4042 filter = hlua_channel_filter(L, 1, chn, &output, &input);
4043 if (filter || !IS_HTX_STRM(chn_strm(chn)))
4044 lua_pushinteger(L, input);
4045 else {
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004046 struct htx *htx = htxbuf(&chn->buf);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004047
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004048 lua_pushinteger(L, htx->data - co_data(chn));
4049 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004050 return 1;
4051}
4052
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004053/* Returns true if the channel is full. */
4054__LJMP static int hlua_channel_is_full(lua_State *L)
4055{
4056 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004057
4058 MAY_LJMP(check_args(L, 1, "is_full"));
4059 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01004060 /* ignore the reserve, we are not on a producer side (ie in an
4061 * applet).
4062 */
4063 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004064 return 1;
4065}
4066
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004067/* Returns true if the channel may still receive data. */
4068__LJMP static int hlua_channel_may_recv(lua_State *L)
4069{
4070 struct channel *chn;
4071
4072 MAY_LJMP(check_args(L, 1, "may_recv"));
4073 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4074 lua_pushboolean(L, (!channel_input_closed(chn) && channel_may_recv(chn)));
4075 return 1;
4076}
4077
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01004078/* Returns true if the channel is the response channel. */
4079__LJMP static int hlua_channel_is_resp(lua_State *L)
4080{
4081 struct channel *chn;
4082
4083 MAY_LJMP(check_args(L, 1, "is_resp"));
4084 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4085
4086 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
4087 return 1;
4088}
4089
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004090/* Just returns the number of bytes available in the output
4091 * side of the buffer. This function never fails.
4092 */
4093__LJMP static int hlua_channel_get_out_len(lua_State *L)
4094{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004095 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004096 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004097
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004098 MAY_LJMP(check_args(L, 1, "output"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004099 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004100
4101 output = co_data(chn);
4102 input = ci_data(chn);
4103 hlua_channel_filter(L, 1, chn, &output, &input);
4104
4105 lua_pushinteger(L, output);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004106 return 1;
4107}
4108
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004109/*
4110 *
4111 *
4112 * Class Fetches
4113 *
4114 *
4115 */
4116
4117/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004118 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004119 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004120__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004121{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004122 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004123}
4124
4125/* This function creates and push in the stack a fetch object according
4126 * with a current TXN.
4127 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004128static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004129{
Willy Tarreau7073c472015-04-06 11:15:40 +02004130 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004131
4132 /* Check stack size. */
4133 if (!lua_checkstack(L, 3))
4134 return 0;
4135
4136 /* Create the object: obj[0] = userdata.
4137 * Note that the base of the Fetches object is the
4138 * transaction object.
4139 */
4140 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004141 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004142 lua_rawseti(L, -2, 0);
4143
Willy Tarreau7073c472015-04-06 11:15:40 +02004144 hsmp->s = txn->s;
4145 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004146 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004147 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004148
4149 /* Pop a class sesison metatable and affect it to the userdata. */
4150 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
4151 lua_setmetatable(L, -2);
4152
4153 return 1;
4154}
4155
4156/* This function is an LUA binding. It is called with each sample-fetch.
4157 * It uses closure argument to store the associated sample-fetch. It
4158 * returns only one argument or throws an error. An error is thrown
4159 * only if an error is encountered during the argument parsing. If
4160 * the "sample-fetch" function fails, nil is returned.
4161 */
4162__LJMP static int hlua_run_sample_fetch(lua_State *L)
4163{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004164 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01004165 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004166 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004167 int i;
4168 struct sample smp;
4169
4170 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004171 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004172
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004173 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004174 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004175
Thierry FOURNIERca988662015-12-20 18:43:03 +01004176 /* Check execution authorization. */
4177 if (f->use & SMP_USE_HTTP_ANY &&
4178 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
4179 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
4180 "is not available in Lua services", f->kw);
4181 WILL_LJMP(lua_error(L));
4182 }
4183
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004184 /* Get extra arguments. */
4185 for (i = 0; i < lua_gettop(L) - 1; i++) {
4186 if (i >= ARGM_NBARGS)
4187 break;
4188 hlua_lua2arg(L, i + 2, &args[i]);
4189 }
4190 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004191 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004192
4193 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004194 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004195
4196 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01004197 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004198 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004199 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004200 }
4201
4202 /* Initialise the sample. */
4203 memset(&smp, 0, sizeof(smp));
4204
4205 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01004206 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02004207 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004208 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004209 lua_pushstring(L, "");
4210 else
4211 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004212 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004213 }
4214
4215 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004216 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004217 hlua_smp2lua_str(L, &smp);
4218 else
4219 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004220
4221 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004222 free_args(args);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004223 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004224
4225 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004226 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004227 WILL_LJMP(lua_error(L));
4228 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004229}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004230
4231/*
4232 *
4233 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004234 * Class Converters
4235 *
4236 *
4237 */
4238
4239/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004240 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004241 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004242__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004243{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004244 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004245}
4246
4247/* This function creates and push in the stack a Converters object
4248 * according with a current TXN.
4249 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004250static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004251{
Willy Tarreau7073c472015-04-06 11:15:40 +02004252 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004253
4254 /* Check stack size. */
4255 if (!lua_checkstack(L, 3))
4256 return 0;
4257
4258 /* Create the object: obj[0] = userdata.
4259 * Note that the base of the Converters object is the
4260 * same than the TXN object.
4261 */
4262 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004263 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004264 lua_rawseti(L, -2, 0);
4265
Willy Tarreau7073c472015-04-06 11:15:40 +02004266 hsmp->s = txn->s;
4267 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004268 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004269 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004270
Willy Tarreau87b09662015-04-03 00:22:06 +02004271 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004272 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
4273 lua_setmetatable(L, -2);
4274
4275 return 1;
4276}
4277
4278/* This function is an LUA binding. It is called with each converter.
4279 * It uses closure argument to store the associated converter. It
4280 * returns only one argument or throws an error. An error is thrown
4281 * only if an error is encountered during the argument parsing. If
4282 * the converter function function fails, nil is returned.
4283 */
4284__LJMP static int hlua_run_sample_conv(lua_State *L)
4285{
Willy Tarreauda5f1082015-04-06 11:17:13 +02004286 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004287 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004288 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004289 int i;
4290 struct sample smp;
4291
4292 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004293 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004294
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004295 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004296 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004297
4298 /* Get extra arguments. */
4299 for (i = 0; i < lua_gettop(L) - 2; i++) {
4300 if (i >= ARGM_NBARGS)
4301 break;
4302 hlua_lua2arg(L, i + 3, &args[i]);
4303 }
4304 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004305 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004306
4307 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004308 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004309
4310 /* Run the special args checker. */
4311 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
4312 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004313 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004314 }
4315
4316 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004317 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004318 if (!hlua_lua2smp(L, 2, &smp)) {
4319 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004320 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004321 }
4322
Willy Tarreau1777ea62016-03-10 16:15:46 +01004323 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
4324
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004325 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004326 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004327 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004328 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004329 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004330 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004331 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
4332 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004333 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004334 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004335 }
4336
4337 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02004338 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004339 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004340 lua_pushstring(L, "");
4341 else
Willy Tarreaua678b432015-08-28 10:14:59 +02004342 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004343 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004344 }
4345
4346 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004347 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004348 hlua_smp2lua_str(L, &smp);
4349 else
4350 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004351 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004352 free_args(args);
Willy Tarreaua678b432015-08-28 10:14:59 +02004353 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004354
4355 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004356 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004357 WILL_LJMP(lua_error(L));
4358 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004359}
4360
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004361/*
4362 *
4363 *
4364 * Class AppletTCP
4365 *
4366 *
4367 */
4368
4369/* Returns a struct hlua_txn if the stack entry "ud" is
4370 * a class stream, otherwise it throws an error.
4371 */
4372__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
4373{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004374 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004375}
4376
4377/* This function creates and push in the stack an Applet object
4378 * according with a current TXN.
4379 */
4380static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
4381{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004382 struct hlua_appctx *luactx;
Willy Tarreau0698c802022-05-11 14:09:57 +02004383 struct stream *s = appctx_strm(ctx);
Christopher Faulet2da02ae2022-02-24 13:45:27 +01004384 struct proxy *p;
4385
4386 ALREADY_CHECKED(s);
4387 p = s->be;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004388
4389 /* Check stack size. */
4390 if (!lua_checkstack(L, 3))
4391 return 0;
4392
4393 /* Create the object: obj[0] = userdata.
4394 * Note that the base of the Converters object is the
4395 * same than the TXN object.
4396 */
4397 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004398 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004399 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004400 luactx->appctx = ctx;
4401 luactx->htxn.s = s;
4402 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004403
4404 /* Create the "f" field that contains a list of fetches. */
4405 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004406 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004407 return 0;
4408 lua_settable(L, -3);
4409
4410 /* Create the "sf" field that contains a list of stringsafe fetches. */
4411 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004412 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004413 return 0;
4414 lua_settable(L, -3);
4415
4416 /* Create the "c" field that contains a list of converters. */
4417 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004418 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004419 return 0;
4420 lua_settable(L, -3);
4421
4422 /* Create the "sc" field that contains a list of stringsafe converters. */
4423 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004424 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004425 return 0;
4426 lua_settable(L, -3);
4427
4428 /* Pop a class stream metatable and affect it to the table. */
4429 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
4430 lua_setmetatable(L, -2);
4431
4432 return 1;
4433}
4434
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004435__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
4436{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004437 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004438 struct stream *s;
4439 const char *name;
4440 size_t len;
4441 struct sample smp;
4442
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004443 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4444 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004445
4446 /* It is useles to retrieve the stream, but this function
4447 * runs only in a stream context.
4448 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004449 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004450 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004451 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004452
4453 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004454 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004455 hlua_lua2smp(L, 3, &smp);
4456
4457 /* Store the sample in a variable. */
4458 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004459
4460 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4461 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4462 else
4463 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4464
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004465 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004466}
4467
4468__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
4469{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004470 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004471 struct stream *s;
4472 const char *name;
4473 size_t len;
4474 struct sample smp;
4475
4476 MAY_LJMP(check_args(L, 2, "unset_var"));
4477
4478 /* It is useles to retrieve the stream, but this function
4479 * runs only in a stream context.
4480 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004481 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004482 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004483 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004484
4485 /* Unset the variable. */
4486 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004487 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4488 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004489}
4490
4491__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
4492{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004493 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004494 struct stream *s;
4495 const char *name;
4496 size_t len;
4497 struct sample smp;
4498
4499 MAY_LJMP(check_args(L, 2, "get_var"));
4500
4501 /* It is useles to retrieve the stream, but this function
4502 * runs only in a stream context.
4503 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004504 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004505 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004506 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004507
4508 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02004509 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004510 lua_pushnil(L);
4511 return 1;
4512 }
4513
4514 return hlua_smp2lua(L, &smp);
4515}
4516
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004517__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
4518{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004519 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4520 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004521 struct hlua *hlua;
4522
4523 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004524 if (!s->hlua)
4525 return 0;
4526 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004527
4528 MAY_LJMP(check_args(L, 2, "set_priv"));
4529
4530 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004531 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004532
4533 /* Get and store new value. */
4534 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4535 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4536
4537 return 0;
4538}
4539
4540__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
4541{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004542 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4543 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004544 struct hlua *hlua;
4545
4546 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004547 if (!s->hlua) {
4548 lua_pushnil(L);
4549 return 1;
4550 }
4551 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004552
4553 /* Push configuration index in the stack. */
4554 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4555
4556 return 1;
4557}
4558
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004559/* If expected data not yet available, it returns a yield. This function
4560 * consumes the data in the buffer. It returns a string containing the
4561 * data. This string can be empty.
4562 */
4563__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
4564{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004565 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004566 struct stconn *sc = appctx_sc(luactx->appctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004567 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004568 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004569 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004570 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004571 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004572
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004573 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004574 ret = co_getline_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004575
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004576 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004577 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004578 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004579 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004580 }
4581
4582 /* End of data: commit the total strings and return. */
4583 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004584 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004585 return 1;
4586 }
4587
4588 /* Ensure that the block 2 length is usable. */
4589 if (ret == 1)
4590 len2 = 0;
4591
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004592 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004593 luaL_addlstring(&luactx->b, blk1, len1);
4594 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004595
4596 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004597 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004598 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004599 return 1;
4600}
4601
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004602/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004603__LJMP static int hlua_applet_tcp_getline(lua_State *L)
4604{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004605 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004606
4607 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004608 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004609
4610 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
4611}
4612
4613/* If expected data not yet available, it returns a yield. This function
4614 * consumes the data in the buffer. It returns a string containing the
4615 * data. This string can be empty.
4616 */
4617__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
4618{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004619 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004620 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004621 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004622 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004623 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004624 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004625 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004626 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004627
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004628 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004629 ret = co_getblk_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004630
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004631 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004632 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004633 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004634 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004635 }
4636
4637 /* End of data: commit the total strings and return. */
4638 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004639 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004640 return 1;
4641 }
4642
4643 /* Ensure that the block 2 length is usable. */
4644 if (ret == 1)
4645 len2 = 0;
4646
4647 if (len == -1) {
4648
4649 /* If len == -1, catenate all the data avalaile and
4650 * yield because we want to get all the data until
4651 * the end of data stream.
4652 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004653 luaL_addlstring(&luactx->b, blk1, len1);
4654 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004655 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004656 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004657 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004658
4659 } else {
4660
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004661 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004662 if (len1 > len)
4663 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004664 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004665 len -= len1;
4666
4667 /* Copy the second block. */
4668 if (len2 > len)
4669 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004670 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004671 len -= len2;
4672
4673 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004674 co_skip(sc_oc(sc), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004675
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004676 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004677 if (len > 0) {
4678 lua_pushinteger(L, len);
4679 lua_replace(L, 2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004680 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004681 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004682 }
4683
4684 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004685 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004686 return 1;
4687 }
4688
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004689 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004690 hlua_pusherror(L, "Lua: internal error");
4691 WILL_LJMP(lua_error(L));
4692 return 0;
4693}
4694
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004695/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004696__LJMP static int hlua_applet_tcp_recv(lua_State *L)
4697{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004698 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004699 int len = -1;
4700
4701 if (lua_gettop(L) > 2)
4702 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4703 if (lua_gettop(L) >= 2) {
4704 len = MAY_LJMP(luaL_checkinteger(L, 2));
4705 lua_pop(L, 1);
4706 }
4707
4708 /* Confirm or set the required length */
4709 lua_pushinteger(L, len);
4710
4711 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004712 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004713
4714 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
4715}
4716
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004717/* Append data in the output side of the buffer. This data is immediately
4718 * sent. The function returns the amount of data written. If the buffer
4719 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004720 * if the channel is closed.
4721 */
4722__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4723{
4724 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004725 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004726 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4727 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004728 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004729 struct channel *chn = sc_ic(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004730 int max;
4731
4732 /* Get the max amount of data which can write as input in the channel. */
4733 max = channel_recv_max(chn);
4734 if (max > (len - l))
4735 max = len - l;
4736
4737 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004738 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004739
4740 /* update counters. */
4741 l += max;
4742 lua_pop(L, 1);
4743 lua_pushinteger(L, l);
4744
4745 /* If some data is not send, declares the situation to the
4746 * applet, and returns a yield.
4747 */
4748 if (l < len) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02004749 sc_need_room(sc);
Willy Tarreau9635e032018-10-16 17:52:55 +02004750 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004751 }
4752
4753 return 1;
4754}
4755
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004756/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004757 * yield the LUA process, and resume it without checking the
4758 * input arguments.
4759 */
4760__LJMP static int hlua_applet_tcp_send(lua_State *L)
4761{
4762 MAY_LJMP(check_args(L, 2, "send"));
4763 lua_pushinteger(L, 0);
4764
4765 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
4766}
4767
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004768/*
4769 *
4770 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004771 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004772 *
4773 *
4774 */
4775
4776/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004777 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004778 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004779__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004780{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004781 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004782}
4783
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004784/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004785 * according with a current TXN.
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004786 * It relies on the caller to have already reserved the room in ctx->svcctx
4787 * for the local storage of hlua_http_ctx.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004788 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004789static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004790{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004791 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004792 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01004793 struct hlua_txn htxn;
Willy Tarreau0698c802022-05-11 14:09:57 +02004794 struct stream *s = appctx_strm(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004795 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02004796 struct htx *htx;
4797 struct htx_blk *blk;
4798 struct htx_sl *sl;
4799 struct ist path;
4800 unsigned long long len = 0;
4801 int32_t pos;
Amaury Denoyellec453f952021-07-06 11:40:12 +02004802 struct http_uri_parser parser;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004803
4804 /* Check stack size. */
4805 if (!lua_checkstack(L, 3))
4806 return 0;
4807
4808 /* Create the object: obj[0] = userdata.
4809 * Note that the base of the Converters object is the
4810 * same than the TXN object.
4811 */
4812 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004813 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004814 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004815 luactx->appctx = ctx;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004816 http_ctx->status = 200; /* Default status code returned. */
4817 http_ctx->reason = NULL; /* Use default reason based on status */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004818 luactx->htxn.s = s;
4819 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004820
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004821 /* Create the "f" field that contains a list of fetches. */
4822 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004823 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004824 return 0;
4825 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004826
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004827 /* Create the "sf" field that contains a list of stringsafe fetches. */
4828 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004829 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004830 return 0;
4831 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004832
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004833 /* Create the "c" field that contains a list of converters. */
4834 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004835 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004836 return 0;
4837 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004838
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004839 /* Create the "sc" field that contains a list of stringsafe converters. */
4840 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004841 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004842 return 0;
4843 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004844
Christopher Fauleta2097962019-07-15 16:25:33 +02004845 htx = htxbuf(&s->req.buf);
4846 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004847 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004848 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004849
Christopher Fauleta2097962019-07-15 16:25:33 +02004850 /* Stores the request method. */
4851 lua_pushstring(L, "method");
4852 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4853 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004854
Christopher Fauleta2097962019-07-15 16:25:33 +02004855 /* Stores the http version. */
4856 lua_pushstring(L, "version");
4857 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4858 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004859
Christopher Fauleta2097962019-07-15 16:25:33 +02004860 /* creates an array of headers. hlua_http_get_headers() crates and push
4861 * the array on the top of the stack.
4862 */
4863 lua_pushstring(L, "headers");
4864 htxn.s = s;
4865 htxn.p = px;
4866 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004867 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004868 return 0;
4869 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004870
Amaury Denoyellec453f952021-07-06 11:40:12 +02004871 parser = http_uri_parser_init(htx_sl_req_uri(sl));
4872 path = http_parse_path(&parser);
Tim Duesterhused526372020-03-05 17:56:33 +01004873 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004874 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004875
Christopher Fauleta2097962019-07-15 16:25:33 +02004876 p = path.ptr;
Tim Duesterhus4c8f75f2021-11-06 15:14:44 +01004877 end = istend(path);
Christopher Fauleta2097962019-07-15 16:25:33 +02004878 q = p;
4879 while (q < end && *q != '?')
4880 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004881
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004882 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004883 lua_pushstring(L, "path");
4884 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004885 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004886
Christopher Fauleta2097962019-07-15 16:25:33 +02004887 /* Stores the query string. */
4888 lua_pushstring(L, "qs");
4889 if (*q == '?')
4890 q++;
4891 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004892 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004893 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004894
Christopher Fauleta2097962019-07-15 16:25:33 +02004895 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4896 struct htx_blk *blk = htx_get_blk(htx, pos);
4897 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004898
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004899 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02004900 break;
4901 if (type == HTX_BLK_DATA)
4902 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004903 }
Christopher Faulet2e47e3a2023-01-13 11:40:24 +01004904 if (htx->extra != HTX_UNKOWN_PAYLOAD_LENGTH)
Christopher Fauleta2097962019-07-15 16:25:33 +02004905 len += htx->extra;
4906
4907 /* Stores the request path. */
4908 lua_pushstring(L, "length");
4909 lua_pushinteger(L, len);
4910 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004911
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004912 /* Create an empty array of HTTP request headers. */
4913 lua_pushstring(L, "response");
4914 lua_newtable(L);
4915 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004916
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004917 /* Pop a class stream metatable and affect it to the table. */
4918 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4919 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004920
4921 return 1;
4922}
4923
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004924__LJMP static int hlua_applet_http_set_var(lua_State *L)
4925{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004926 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004927 struct stream *s;
4928 const char *name;
4929 size_t len;
4930 struct sample smp;
4931
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004932 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4933 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004934
4935 /* It is useles to retrieve the stream, but this function
4936 * runs only in a stream context.
4937 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004938 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004939 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004940 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004941
4942 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004943 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004944 hlua_lua2smp(L, 3, &smp);
4945
4946 /* Store the sample in a variable. */
4947 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004948
4949 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4950 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4951 else
4952 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4953
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004954 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004955}
4956
4957__LJMP static int hlua_applet_http_unset_var(lua_State *L)
4958{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004959 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004960 struct stream *s;
4961 const char *name;
4962 size_t len;
4963 struct sample smp;
4964
4965 MAY_LJMP(check_args(L, 2, "unset_var"));
4966
4967 /* It is useles to retrieve the stream, but this function
4968 * runs only in a stream context.
4969 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004970 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004971 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004972 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004973
4974 /* Unset the variable. */
4975 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004976 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4977 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004978}
4979
4980__LJMP static int hlua_applet_http_get_var(lua_State *L)
4981{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004982 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004983 struct stream *s;
4984 const char *name;
4985 size_t len;
4986 struct sample smp;
4987
4988 MAY_LJMP(check_args(L, 2, "get_var"));
4989
4990 /* It is useles to retrieve the stream, but this function
4991 * runs only in a stream context.
4992 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004993 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004994 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004995 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004996
4997 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02004998 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004999 lua_pushnil(L);
5000 return 1;
5001 }
5002
5003 return hlua_smp2lua(L, &smp);
5004}
5005
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005006__LJMP static int hlua_applet_http_set_priv(lua_State *L)
5007{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005008 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5009 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005010 struct hlua *hlua;
5011
5012 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005013 if (!s->hlua)
5014 return 0;
5015 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005016
5017 MAY_LJMP(check_args(L, 2, "set_priv"));
5018
5019 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005020 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005021
5022 /* Get and store new value. */
5023 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5024 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5025
5026 return 0;
5027}
5028
5029__LJMP static int hlua_applet_http_get_priv(lua_State *L)
5030{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005031 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5032 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005033 struct hlua *hlua;
5034
5035 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005036 if (!s->hlua) {
5037 lua_pushnil(L);
5038 return 1;
5039 }
5040 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005041
5042 /* Push configuration index in the stack. */
5043 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5044
5045 return 1;
5046}
5047
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005048/* If expected data not yet available, it returns a yield. This function
5049 * consumes the data in the buffer. It returns a string containing the
5050 * data. This string can be empty.
5051 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005052__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005053{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005054 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005055 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005056 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005057 struct htx *htx;
5058 struct htx_blk *blk;
5059 size_t count;
5060 int stop = 0;
5061
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005062 htx = htx_from_buf(&req->buf);
5063 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02005064 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01005065
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005066 while (count && !stop && blk) {
5067 enum htx_blk_type type = htx_get_blk_type(blk);
5068 uint32_t sz = htx_get_blksz(blk);
5069 struct ist v;
5070 uint32_t vlen;
5071 char *nl;
5072
5073 vlen = sz;
5074 if (vlen > count) {
5075 if (type != HTX_BLK_DATA)
5076 break;
5077 vlen = count;
5078 }
5079
5080 switch (type) {
5081 case HTX_BLK_UNUSED:
5082 break;
5083
5084 case HTX_BLK_DATA:
5085 v = htx_get_blk_value(htx, blk);
5086 v.len = vlen;
5087 nl = istchr(v, '\n');
5088 if (nl != NULL) {
5089 stop = 1;
5090 vlen = nl - v.ptr + 1;
5091 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02005092 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005093 break;
5094
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005095 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005096 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005097 stop = 1;
5098 break;
5099
5100 default:
5101 break;
5102 }
5103
Willy Tarreau84240042022-02-28 16:51:23 +01005104 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005105 count -= vlen;
5106 if (sz == vlen)
5107 blk = htx_remove_blk(htx, blk);
5108 else {
5109 htx_cut_data_blk(htx, blk, vlen);
5110 break;
5111 }
5112 }
5113
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005114 /* The message was fully consumed and no more data are expected
5115 * (EOM flag set).
5116 */
Christopher Faulet4a209722022-08-29 15:37:16 +02005117 if (htx_is_empty(htx) && (req->flags & CF_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005118 stop = 1;
5119
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005120 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005121 if (!stop) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02005122 applet_need_more_data(luactx->appctx);
Christopher Fauleta2097962019-07-15 16:25:33 +02005123 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005124 }
5125
5126 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005127 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005128 return 1;
5129}
5130
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005131
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005132/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005133__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005134{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005135 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005136
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005137 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005138 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005139
Christopher Fauleta2097962019-07-15 16:25:33 +02005140 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005141}
5142
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005143/* If expected data not yet available, it returns a yield. This function
5144 * consumes the data in the buffer. It returns a string containing the
5145 * data. This string can be empty.
5146 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005147__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005148{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005149 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005150 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005151 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005152 struct htx *htx;
5153 struct htx_blk *blk;
5154 size_t count;
5155 int len;
5156
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005157 htx = htx_from_buf(&req->buf);
5158 len = MAY_LJMP(luaL_checkinteger(L, 2));
5159 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02005160 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005161 while (count && len && blk) {
5162 enum htx_blk_type type = htx_get_blk_type(blk);
5163 uint32_t sz = htx_get_blksz(blk);
5164 struct ist v;
5165 uint32_t vlen;
5166
5167 vlen = sz;
5168 if (len > 0 && vlen > len)
5169 vlen = len;
5170 if (vlen > count) {
5171 if (type != HTX_BLK_DATA)
5172 break;
5173 vlen = count;
5174 }
5175
5176 switch (type) {
5177 case HTX_BLK_UNUSED:
5178 break;
5179
5180 case HTX_BLK_DATA:
5181 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02005182 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005183 break;
5184
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005185 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005186 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005187 len = 0;
5188 break;
5189
5190 default:
5191 break;
5192 }
5193
Willy Tarreau84240042022-02-28 16:51:23 +01005194 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005195 count -= vlen;
5196 if (len > 0)
5197 len -= vlen;
5198 if (sz == vlen)
5199 blk = htx_remove_blk(htx, blk);
5200 else {
5201 htx_cut_data_blk(htx, blk, vlen);
5202 break;
5203 }
5204 }
5205
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005206 /* The message was fully consumed and no more data are expected
5207 * (EOM flag set).
5208 */
Christopher Faulet4a209722022-08-29 15:37:16 +02005209 if (htx_is_empty(htx) && (req->flags & CF_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005210 len = 0;
5211
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005212 htx_to_buf(htx, &req->buf);
5213
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005214 /* If we are no other data available, yield waiting for new data. */
5215 if (len) {
5216 if (len > 0) {
5217 lua_pushinteger(L, len);
5218 lua_replace(L, 2);
5219 }
Willy Tarreau90e8b452022-05-25 18:21:43 +02005220 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02005221 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005222 }
5223
5224 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005225 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005226 return 1;
5227}
5228
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005229/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005230__LJMP static int hlua_applet_http_recv(lua_State *L)
5231{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005232 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005233 int len = -1;
5234
5235 /* Check arguments. */
5236 if (lua_gettop(L) > 2)
5237 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
5238 if (lua_gettop(L) >= 2) {
5239 len = MAY_LJMP(luaL_checkinteger(L, 2));
5240 lua_pop(L, 1);
5241 }
5242
Christopher Fauleta2097962019-07-15 16:25:33 +02005243 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005244
Christopher Fauleta2097962019-07-15 16:25:33 +02005245 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005246 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005247
Christopher Fauleta2097962019-07-15 16:25:33 +02005248 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005249}
5250
5251/* Append data in the output side of the buffer. This data is immediately
5252 * sent. The function returns the amount of data written. If the buffer
5253 * cannot contain the data, the function yields. The function returns -1
5254 * if the channel is closed.
5255 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005256__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005257{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005258 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005259 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005260 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005261 struct htx *htx = htx_from_buf(&res->buf);
5262 const char *data;
5263 size_t len;
5264 int l = MAY_LJMP(luaL_checkinteger(L, 3));
5265 int max;
5266
Christopher Faulet9060fc02019-07-03 11:39:30 +02005267 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005268 if (!max)
5269 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005270
5271 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
5272
5273 /* Get the max amount of data which can write as input in the channel. */
5274 if (max > (len - l))
5275 max = len - l;
5276
5277 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02005278 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005279 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005280
5281 /* update counters. */
5282 l += max;
5283 lua_pop(L, 1);
5284 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005285
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005286 /* If some data is not send, declares the situation to the
5287 * applet, and returns a yield.
5288 */
5289 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005290 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005291 htx_to_buf(htx, &res->buf);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005292 sc_need_room(sc);
Willy Tarreau9635e032018-10-16 17:52:55 +02005293 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005294 }
5295
Christopher Fauleta2097962019-07-15 16:25:33 +02005296 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005297 return 1;
5298}
5299
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005300/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005301 * yield the LUA process, and resume it without checking the
5302 * input arguments.
5303 */
5304__LJMP static int hlua_applet_http_send(lua_State *L)
5305{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005306 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005307 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005308
5309 /* We want to send some data. Headers must be sent. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005310 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005311 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
5312 WILL_LJMP(lua_error(L));
5313 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005314
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005315 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02005316 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005317
Christopher Fauleta2097962019-07-15 16:25:33 +02005318 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005319}
5320
5321__LJMP static int hlua_applet_http_addheader(lua_State *L)
5322{
5323 const char *name;
5324 int ret;
5325
5326 MAY_LJMP(hlua_checkapplet_http(L, 1));
5327 name = MAY_LJMP(luaL_checkstring(L, 2));
5328 MAY_LJMP(luaL_checkstring(L, 3));
5329
5330 /* Push in the stack the "response" entry. */
5331 ret = lua_getfield(L, 1, "response");
5332 if (ret != LUA_TTABLE) {
5333 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
5334 "is expected as an array. %s found", lua_typename(L, ret));
5335 WILL_LJMP(lua_error(L));
5336 }
5337
5338 /* check if the header is already registered if it is not
5339 * the case, register it.
5340 */
5341 ret = lua_getfield(L, -1, name);
5342 if (ret == LUA_TNIL) {
5343
5344 /* Entry not found. */
5345 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
5346
5347 /* Insert the new header name in the array in the top of the stack.
5348 * It left the new array in the top of the stack.
5349 */
5350 lua_newtable(L);
5351 lua_pushvalue(L, 2);
5352 lua_pushvalue(L, -2);
5353 lua_settable(L, -4);
5354
5355 } else if (ret != LUA_TTABLE) {
5356
5357 /* corruption error. */
5358 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
5359 "is expected as an array. %s found", name, lua_typename(L, ret));
5360 WILL_LJMP(lua_error(L));
5361 }
5362
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005363 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005364 * the header value as new entry.
5365 */
5366 lua_pushvalue(L, 3);
5367 ret = lua_rawlen(L, -2);
5368 lua_rawseti(L, -2, ret + 1);
5369 lua_pushboolean(L, 1);
5370 return 1;
5371}
5372
5373__LJMP static int hlua_applet_http_status(lua_State *L)
5374{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005375 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005376 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005377 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005378 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005379
5380 if (status < 100 || status > 599) {
5381 lua_pushboolean(L, 0);
5382 return 1;
5383 }
5384
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005385 http_ctx->status = status;
5386 http_ctx->reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005387 lua_pushboolean(L, 1);
5388 return 1;
5389}
5390
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005391
Christopher Fauleta2097962019-07-15 16:25:33 +02005392__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005393{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005394 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005395 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02005396 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005397 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005398 struct htx *htx;
5399 struct htx_sl *sl;
5400 struct h1m h1m;
5401 const char *status, *reason;
5402 const char *name, *value;
5403 size_t nlen, vlen;
5404 unsigned int flags;
5405
5406 /* Send the message at once. */
5407 htx = htx_from_buf(&res->buf);
5408 h1m_init_res(&h1m);
5409
5410 /* Use the same http version than the request. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005411 status = ultoa_r(http_ctx->status, trash.area, trash.size);
5412 reason = http_ctx->reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005413 if (reason == NULL)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005414 reason = http_get_reason(http_ctx->status);
5415 if (http_ctx->flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005416 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5417 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
5418 }
5419 else {
5420 flags = HTX_SL_F_IS_RESP;
5421 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
5422 }
5423 if (!sl) {
5424 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005425 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005426 WILL_LJMP(lua_error(L));
5427 }
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005428 sl->info.res.status = http_ctx->status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005429
5430 /* Get the array associated to the field "response" in the object AppletHTTP. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005431 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
5432 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005433 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005434 WILL_LJMP(lua_error(L));
5435 }
5436
5437 /* Browse the list of headers. */
5438 lua_pushnil(L);
5439 while(lua_next(L, -2) != 0) {
5440 /* We expect a string as -2. */
5441 if (lua_type(L, -2) != LUA_TSTRING) {
5442 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005443 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005444 lua_typename(L, lua_type(L, -2)));
5445 WILL_LJMP(lua_error(L));
5446 }
5447 name = lua_tolstring(L, -2, &nlen);
5448
5449 /* We expect an array as -1. */
5450 if (lua_type(L, -1) != LUA_TTABLE) {
5451 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 +02005452 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005453 name,
5454 lua_typename(L, lua_type(L, -1)));
5455 WILL_LJMP(lua_error(L));
5456 }
5457
5458 /* Browse the table who is on the top of the stack. */
5459 lua_pushnil(L);
5460 while(lua_next(L, -2) != 0) {
5461 int id;
5462
5463 /* We expect a number as -2. */
5464 if (lua_type(L, -2) != LUA_TNUMBER) {
5465 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 +02005466 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005467 name,
5468 lua_typename(L, lua_type(L, -2)));
5469 WILL_LJMP(lua_error(L));
5470 }
5471 id = lua_tointeger(L, -2);
5472
5473 /* We expect a string as -2. */
5474 if (lua_type(L, -1) != LUA_TSTRING) {
5475 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 +02005476 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005477 name, id,
5478 lua_typename(L, lua_type(L, -1)));
5479 WILL_LJMP(lua_error(L));
5480 }
5481 value = lua_tolstring(L, -1, &vlen);
5482
5483 /* Simple Protocol checks. */
Christopher Faulet545fbba2021-09-28 09:36:25 +02005484 if (isteqi(ist2(name, nlen), ist("transfer-encoding"))) {
5485 int ret;
5486
5487 ret = h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
5488 if (ret < 0) {
5489 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
5490 luactx->appctx->rule->arg.hlua_rule->fcn->name,
5491 name);
5492 WILL_LJMP(lua_error(L));
5493 }
5494 else if (ret == 0)
5495 goto next; /* Skip it */
5496 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005497 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
5498 struct ist v = ist2(value, vlen);
5499 int ret;
5500
5501 ret = h1_parse_cont_len_header(&h1m, &v);
5502 if (ret < 0) {
5503 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005504 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005505 name);
5506 WILL_LJMP(lua_error(L));
5507 }
5508 else if (ret == 0)
5509 goto next; /* Skip it */
5510 }
5511
5512 /* Add a new header */
5513 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
5514 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005515 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005516 name);
5517 WILL_LJMP(lua_error(L));
5518 }
5519 next:
5520 /* Remove the array from the stack, and get next element with a remaining string. */
5521 lua_pop(L, 1);
5522 }
5523
5524 /* Remove the array from the stack, and get next element with a remaining string. */
5525 lua_pop(L, 1);
5526 }
5527
5528 if (h1m.flags & H1_MF_CHNK)
5529 h1m.flags &= ~H1_MF_CLEN;
5530 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5531 h1m.flags |= H1_MF_XFER_LEN;
5532
5533 /* Uset HTX start-line flags */
5534 if (h1m.flags & H1_MF_XFER_ENC)
5535 flags |= HTX_SL_F_XFER_ENC;
5536 if (h1m.flags & H1_MF_XFER_LEN) {
5537 flags |= HTX_SL_F_XFER_LEN;
5538 if (h1m.flags & H1_MF_CHNK)
5539 flags |= HTX_SL_F_CHNK;
5540 else if (h1m.flags & H1_MF_CLEN)
5541 flags |= HTX_SL_F_CLEN;
5542 if (h1m.body_len == 0)
5543 flags |= HTX_SL_F_BODYLESS;
5544 }
5545 sl->flags |= flags;
5546
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005547 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005548 * and the status code implies the presence of a message body, we must
5549 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005550 * for the keepalive compliance. If the applet announces a transfer-encoding
5551 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005552 */
5553 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005554 http_ctx->status >= 200 && http_ctx->status != 204 && http_ctx->status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005555 /* Add a new header */
5556 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
5557 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
5558 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005559 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005560 WILL_LJMP(lua_error(L));
5561 }
5562 }
5563
5564 /* Finalize headers. */
5565 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
5566 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005567 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005568 WILL_LJMP(lua_error(L));
5569 }
5570
5571 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
5572 b_reset(&res->buf);
5573 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
5574 WILL_LJMP(lua_error(L));
5575 }
5576
5577 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005578 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005579
5580 /* Headers sent, set the flag. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005581 http_ctx->flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005582 return 0;
5583
5584}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005585/* We will build the status line and the headers of the HTTP response.
5586 * We will try send at once if its not possible, we give back the hand
5587 * waiting for more room.
5588 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005589__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005590{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005591 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005592 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005593 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005594
5595 if (co_data(res)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02005596 sc_need_room(sc);
Christopher Fauleta2097962019-07-15 16:25:33 +02005597 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005598 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005599 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005600}
5601
5602
Christopher Fauleta2097962019-07-15 16:25:33 +02005603__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005604{
Christopher Fauleta2097962019-07-15 16:25:33 +02005605 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005606}
5607
Christopher Fauleta2097962019-07-15 16:25:33 +02005608/*
5609 *
5610 *
5611 * Class HTTP
5612 *
5613 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005614 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005615
5616/* Returns a struct hlua_txn if the stack entry "ud" is
5617 * a class stream, otherwise it throws an error.
5618 */
5619__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005620{
Christopher Fauleta2097962019-07-15 16:25:33 +02005621 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
5622}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005623
Christopher Fauleta2097962019-07-15 16:25:33 +02005624/* This function creates and push in the stack a HTTP object
5625 * according with a current TXN.
5626 */
5627static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
5628{
5629 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005630
Christopher Fauleta2097962019-07-15 16:25:33 +02005631 /* Check stack size. */
5632 if (!lua_checkstack(L, 3))
5633 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005634
Christopher Fauleta2097962019-07-15 16:25:33 +02005635 /* Create the object: obj[0] = userdata.
5636 * Note that the base of the Converters object is the
5637 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005638 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005639 lua_newtable(L);
5640 htxn = lua_newuserdata(L, sizeof(*htxn));
5641 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005642
5643 htxn->s = txn->s;
5644 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02005645 htxn->dir = txn->dir;
5646 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005647
5648 /* Pop a class stream metatable and affect it to the table. */
5649 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
5650 lua_setmetatable(L, -2);
5651
5652 return 1;
5653}
5654
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005655/* This function creates and returns an array containing the status-line
5656 * elements. This function does not fails.
5657 */
5658__LJMP static int hlua_http_get_stline(lua_State *L, struct htx_sl *sl)
5659{
5660 /* Create the table. */
5661 lua_newtable(L);
5662
5663 if (sl->flags & HTX_SL_F_IS_RESP) {
5664 lua_pushstring(L, "version");
5665 lua_pushlstring(L, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl));
5666 lua_settable(L, -3);
5667 lua_pushstring(L, "code");
5668 lua_pushlstring(L, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl));
5669 lua_settable(L, -3);
5670 lua_pushstring(L, "reason");
5671 lua_pushlstring(L, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl));
5672 lua_settable(L, -3);
5673 }
5674 else {
5675 lua_pushstring(L, "method");
5676 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
5677 lua_settable(L, -3);
5678 lua_pushstring(L, "uri");
5679 lua_pushlstring(L, HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl));
5680 lua_settable(L, -3);
5681 lua_pushstring(L, "version");
5682 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
5683 lua_settable(L, -3);
5684 }
5685 return 1;
5686}
5687
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005688/* This function creates ans returns an array of HTTP headers.
5689 * This function does not fails. It is used as wrapper with the
5690 * 2 following functions.
5691 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005692__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005693{
Christopher Fauleta2097962019-07-15 16:25:33 +02005694 struct htx *htx;
5695 int32_t pos;
5696
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005697 /* Create the table. */
5698 lua_newtable(L);
5699
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005700
Christopher Fauleta2097962019-07-15 16:25:33 +02005701 htx = htxbuf(&msg->chn->buf);
5702 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
5703 struct htx_blk *blk = htx_get_blk(htx, pos);
5704 enum htx_blk_type type = htx_get_blk_type(blk);
5705 struct ist n, v;
5706 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005707
Christopher Fauleta2097962019-07-15 16:25:33 +02005708 if (type == HTX_BLK_HDR) {
5709 n = htx_get_blk_name(htx,blk);
5710 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005711 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005712 else if (type == HTX_BLK_EOH)
5713 break;
5714 else
5715 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005716
Christopher Fauleta2097962019-07-15 16:25:33 +02005717 /* Check for existing entry:
5718 * assume that the table is on the top of the stack, and
5719 * push the key in the stack, the function lua_gettable()
5720 * perform the lookup.
5721 */
5722 lua_pushlstring(L, n.ptr, n.len);
5723 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005724
Christopher Fauleta2097962019-07-15 16:25:33 +02005725 switch (lua_type(L, -1)) {
5726 case LUA_TNIL:
5727 /* Table not found, create it. */
5728 lua_pop(L, 1); /* remove the nil value. */
5729 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
5730 lua_newtable(L); /* create and push empty table. */
5731 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5732 lua_rawseti(L, -2, 0); /* index header value (pop it). */
5733 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01005734 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005735
Christopher Fauleta2097962019-07-15 16:25:33 +02005736 case LUA_TTABLE:
5737 /* Entry found: push the value in the table. */
5738 len = lua_rawlen(L, -1);
5739 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5740 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
5741 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
5742 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005743
Christopher Fauleta2097962019-07-15 16:25:33 +02005744 default:
5745 /* Other cases are errors. */
5746 hlua_pusherror(L, "internal error during the parsing of headers.");
5747 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005748 }
5749 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005750 return 1;
5751}
5752
5753__LJMP static int hlua_http_req_get_headers(lua_State *L)
5754{
5755 struct hlua_txn *htxn;
5756
5757 MAY_LJMP(check_args(L, 1, "req_get_headers"));
5758 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5759
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005760 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005761 WILL_LJMP(lua_error(L));
5762
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005763 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005764}
5765
5766__LJMP static int hlua_http_res_get_headers(lua_State *L)
5767{
5768 struct hlua_txn *htxn;
5769
5770 MAY_LJMP(check_args(L, 1, "res_get_headers"));
5771 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5772
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005773 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005774 WILL_LJMP(lua_error(L));
5775
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005776 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005777}
5778
5779/* This function replace full header, or just a value in
5780 * the request or in the response. It is a wrapper fir the
5781 * 4 following functions.
5782 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005783__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005784{
5785 size_t name_len;
5786 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5787 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
5788 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02005789 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02005790 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005791
Dragan Dosen26743032019-04-30 15:54:36 +02005792 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005793 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
5794
Christopher Fauleta2097962019-07-15 16:25:33 +02005795 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005796 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02005797 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005798 return 0;
5799}
5800
5801__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
5802{
5803 struct hlua_txn *htxn;
5804
5805 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5806 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5807
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005808 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005809 WILL_LJMP(lua_error(L));
5810
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005811 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005812}
5813
5814__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
5815{
5816 struct hlua_txn *htxn;
5817
5818 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
5819 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5820
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005821 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005822 WILL_LJMP(lua_error(L));
5823
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005824 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005825}
5826
5827__LJMP static int hlua_http_req_rep_val(lua_State *L)
5828{
5829 struct hlua_txn *htxn;
5830
5831 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5832 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5833
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005834 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005835 WILL_LJMP(lua_error(L));
5836
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005837 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005838}
5839
5840__LJMP static int hlua_http_res_rep_val(lua_State *L)
5841{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005842 struct hlua_txn *htxn;
5843
5844 MAY_LJMP(check_args(L, 4, "res_rep_val"));
5845 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5846
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005847 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005848 WILL_LJMP(lua_error(L));
5849
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005850 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005851}
5852
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005853/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005854 * It is a wrapper for the 2 following functions.
5855 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005856__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005857{
5858 size_t len;
5859 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005860 struct htx *htx = htxbuf(&msg->chn->buf);
5861 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005862
Christopher Fauleta2097962019-07-15 16:25:33 +02005863 ctx.blk = NULL;
5864 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5865 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005866 return 0;
5867}
5868
5869__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5870{
5871 struct hlua_txn *htxn;
5872
5873 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5874 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5875
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005876 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005877 WILL_LJMP(lua_error(L));
5878
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005879 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005880}
5881
5882__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5883{
5884 struct hlua_txn *htxn;
5885
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005886 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005887 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5888
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005889 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005890 WILL_LJMP(lua_error(L));
5891
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005892 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005893}
5894
5895/* This function adds an header. It is a wrapper used by
5896 * the 2 following functions.
5897 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005898__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005899{
5900 size_t name_len;
5901 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5902 size_t value_len;
5903 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005904 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005905
Christopher Fauleta2097962019-07-15 16:25:33 +02005906 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5907 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005908 return 0;
5909}
5910
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005911__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5912{
5913 struct hlua_txn *htxn;
5914
5915 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5916 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5917
5918 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5919 WILL_LJMP(lua_error(L));
5920
5921 return hlua_http_add_hdr(L, &htxn->s->txn->req);
5922}
5923
5924__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5925{
5926 struct hlua_txn *htxn;
5927
5928 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5929 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5930
5931 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
5932 WILL_LJMP(lua_error(L));
5933
5934 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
5935}
5936
5937static int hlua_http_req_set_hdr(lua_State *L)
5938{
5939 struct hlua_txn *htxn;
5940
5941 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5942 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5943
5944 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5945 WILL_LJMP(lua_error(L));
5946
5947 hlua_http_del_hdr(L, &htxn->s->txn->req);
5948 return hlua_http_add_hdr(L, &htxn->s->txn->req);
5949}
5950
5951static int hlua_http_res_set_hdr(lua_State *L)
5952{
5953 struct hlua_txn *htxn;
5954
5955 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
5956 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5957
5958 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
5959 WILL_LJMP(lua_error(L));
5960
5961 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
5962 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
5963}
5964
5965/* This function set the method. */
5966static int hlua_http_req_set_meth(lua_State *L)
5967{
5968 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5969 size_t name_len;
5970 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5971
5972 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5973 WILL_LJMP(lua_error(L));
5974
5975 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
5976 return 1;
5977}
5978
5979/* This function set the method. */
5980static int hlua_http_req_set_path(lua_State *L)
5981{
5982 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5983 size_t name_len;
5984 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5985
5986 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5987 WILL_LJMP(lua_error(L));
5988
5989 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
5990 return 1;
5991}
5992
5993/* This function set the query-string. */
5994static int hlua_http_req_set_query(lua_State *L)
5995{
5996 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5997 size_t name_len;
5998 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5999
6000 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6001 WILL_LJMP(lua_error(L));
6002
6003 /* Check length. */
6004 if (name_len > trash.size - 1) {
6005 lua_pushboolean(L, 0);
6006 return 1;
6007 }
6008
6009 /* Add the mark question as prefix. */
6010 chunk_reset(&trash);
6011 trash.area[trash.data++] = '?';
6012 memcpy(trash.area + trash.data, name, name_len);
6013 trash.data += name_len;
6014
6015 lua_pushboolean(L,
6016 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
6017 return 1;
6018}
6019
6020/* This function set the uri. */
6021static int hlua_http_req_set_uri(lua_State *L)
6022{
6023 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6024 size_t name_len;
6025 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6026
6027 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6028 WILL_LJMP(lua_error(L));
6029
6030 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
6031 return 1;
6032}
6033
6034/* This function set the response code & optionally reason. */
6035static int hlua_http_res_set_status(lua_State *L)
6036{
6037 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6038 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
6039 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6040 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
6041
6042 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6043 WILL_LJMP(lua_error(L));
6044
6045 http_res_set_status(code, reason, htxn->s);
6046 return 0;
6047}
6048
6049/*
6050 *
6051 *
6052 * Class HTTPMessage
6053 *
6054 *
6055 */
6056
6057/* Returns a struct http_msg if the stack entry "ud" is a class HTTPMessage,
6058 * otherwise it throws an error.
6059 */
6060__LJMP static struct http_msg *hlua_checkhttpmsg(lua_State *L, int ud)
6061{
6062 return MAY_LJMP(hlua_checkudata(L, ud, class_http_msg_ref));
6063}
6064
6065/* Creates and pushes on the stack a HTTP object according with a current TXN.
6066 */
Christopher Faulet78c35472020-02-26 17:14:08 +01006067static int hlua_http_msg_new(lua_State *L, struct http_msg *msg)
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006068{
6069 /* Check stack size. */
6070 if (!lua_checkstack(L, 3))
6071 return 0;
6072
6073 lua_newtable(L);
6074 lua_pushlightuserdata(L, msg);
6075 lua_rawseti(L, -2, 0);
6076
6077 /* Create the "channel" field that contains the request channel object. */
6078 lua_pushstring(L, "channel");
6079 if (!hlua_channel_new(L, msg->chn))
6080 return 0;
6081 lua_rawset(L, -3);
6082
6083 /* Pop a class stream metatable and affect it to the table. */
6084 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_msg_ref);
6085 lua_setmetatable(L, -2);
6086
6087 return 1;
6088}
6089
6090/* Helper function returning a filter attached to the HTTP message at the
6091 * position <ud> in the stack, filling the current offset and length of the
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006092 * filter. If no filter is attached, NULL is returned and <offset> and <len> are
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006093 * filled with output and input length respectively.
6094 */
6095static struct filter *hlua_http_msg_filter(lua_State *L, int ud, struct http_msg *msg, size_t *offset, size_t *len)
6096{
6097 struct channel *chn = msg->chn;
6098 struct htx *htx = htxbuf(&chn->buf);
6099 struct filter *filter = NULL;
6100
6101 *offset = co_data(msg->chn);
6102 *len = htx->data - co_data(msg->chn);
6103
6104 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
6105 filter = lua_touserdata (L, -1);
6106 if (msg->msg_state >= HTTP_MSG_DATA) {
6107 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6108
6109 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
6110 *len = flt_ctx->cur_len[CHN_IDX(chn)];
6111 }
6112 }
6113
6114 lua_pop(L, 1);
6115 return filter;
6116}
6117
6118/* Returns true if the channel attached to the HTTP message is the response
6119 * channel.
6120 */
6121__LJMP static int hlua_http_msg_is_resp(lua_State *L)
6122{
6123 struct http_msg *msg;
6124
6125 MAY_LJMP(check_args(L, 1, "is_resp"));
6126 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6127
6128 lua_pushboolean(L, !!(msg->chn->flags & CF_ISRESP));
6129 return 1;
6130}
6131
6132/* Returns an array containing the elements status-line of the HTTP message. It relies
6133 * on hlua_http_get_stline().
6134 */
6135__LJMP static int hlua_http_msg_get_stline(lua_State *L)
6136{
6137 struct http_msg *msg;
6138 struct htx *htx;
6139 struct htx_sl *sl;
6140
6141 MAY_LJMP(check_args(L, 1, "get_stline"));
6142 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6143
6144 if (msg->msg_state > HTTP_MSG_BODY)
6145 WILL_LJMP(lua_error(L));
6146
6147 htx = htxbuf(&msg->chn->buf);
6148 sl = http_get_stline(htx);
6149 if (!sl)
6150 return 0;
6151 return hlua_http_get_stline(L, sl);
6152}
6153
6154/* Returns an array containing all headers of the HTTP message. it relies on
6155 * hlua_http_get_headers().
6156 */
6157__LJMP static int hlua_http_msg_get_headers(lua_State *L)
6158{
6159 struct http_msg *msg;
6160
6161 MAY_LJMP(check_args(L, 1, "get_headers"));
6162 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6163
6164 if (msg->msg_state > HTTP_MSG_BODY)
6165 WILL_LJMP(lua_error(L));
6166
6167 return hlua_http_get_headers(L, msg);
6168}
6169
6170/* Deletes all occurrences of an header in the HTTP message matching on its
6171 * name. It relies on hlua_http_del_hdr().
6172 */
6173__LJMP static int hlua_http_msg_del_hdr(lua_State *L)
6174{
6175 struct http_msg *msg;
6176
6177 MAY_LJMP(check_args(L, 2, "del_header"));
6178 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6179
6180 if (msg->msg_state > HTTP_MSG_BODY)
6181 WILL_LJMP(lua_error(L));
6182
6183 return hlua_http_del_hdr(L, msg);
6184}
6185
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006186/* Matches the full value line of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006187 * message given its name against a regex and replaces it if it matches. It
6188 * relies on hlua_http_rep_hdr().
6189 */
6190__LJMP static int hlua_http_msg_rep_hdr(lua_State *L)
6191{
6192 struct http_msg *msg;
6193
6194 MAY_LJMP(check_args(L, 4, "rep_header"));
6195 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6196
6197 if (msg->msg_state > HTTP_MSG_BODY)
6198 WILL_LJMP(lua_error(L));
6199
6200 return hlua_http_rep_hdr(L, msg, 1);
6201}
6202
Ilya Shipitsinbd6b4be2021-10-15 16:18:21 +05006203/* Matches all comma-separated values of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006204 * message given its name against a regex and replaces it if it matches. It
6205 * relies on hlua_http_rep_hdr().
6206 */
6207__LJMP static int hlua_http_msg_rep_val(lua_State *L)
6208{
6209 struct http_msg *msg;
6210
6211 MAY_LJMP(check_args(L, 4, "rep_value"));
6212 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6213
6214 if (msg->msg_state > HTTP_MSG_BODY)
6215 WILL_LJMP(lua_error(L));
6216
6217 return hlua_http_rep_hdr(L, msg, 0);
6218}
6219
6220/* Add an header in the HTTP message. It relies on hlua_http_add_hdr() */
6221__LJMP static int hlua_http_msg_add_hdr(lua_State *L)
6222{
6223 struct http_msg *msg;
6224
6225 MAY_LJMP(check_args(L, 3, "add_header"));
6226 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6227
6228 if (msg->msg_state > HTTP_MSG_BODY)
6229 WILL_LJMP(lua_error(L));
6230
6231 return hlua_http_add_hdr(L, msg);
6232}
6233
6234/* Add an header in the HTTP message removing existing headers with the same
6235 * name. It relies on hlua_http_del_hdr() and hlua_http_add_hdr().
6236 */
6237__LJMP static int hlua_http_msg_set_hdr(lua_State *L)
6238{
6239 struct http_msg *msg;
6240
6241 MAY_LJMP(check_args(L, 3, "set_header"));
6242 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6243
6244 if (msg->msg_state > HTTP_MSG_BODY)
6245 WILL_LJMP(lua_error(L));
6246
6247 hlua_http_del_hdr(L, msg);
6248 return hlua_http_add_hdr(L, msg);
6249}
6250
6251/* Rewrites the request method. It relies on http_req_replace_stline(). */
6252__LJMP static int hlua_http_msg_set_meth(lua_State *L)
6253{
6254 struct stream *s;
6255 struct http_msg *msg;
6256 const char *name;
6257 size_t name_len;
6258
6259 MAY_LJMP(check_args(L, 2, "set_method"));
6260 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6261 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6262
6263 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6264 WILL_LJMP(lua_error(L));
6265
6266 s = chn_strm(msg->chn);
6267 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, s->be, s) != -1);
6268 return 1;
6269}
6270
6271/* Rewrites the request path. It relies on http_req_replace_stline(). */
6272__LJMP static int hlua_http_msg_set_path(lua_State *L)
6273{
6274 struct stream *s;
6275 struct http_msg *msg;
6276 const char *name;
6277 size_t name_len;
6278
6279 MAY_LJMP(check_args(L, 2, "set_path"));
6280 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6281 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6282
6283 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6284 WILL_LJMP(lua_error(L));
6285
6286 s = chn_strm(msg->chn);
6287 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, s->be, s) != -1);
6288 return 1;
6289}
6290
6291/* Rewrites the request query-string. It relies on http_req_replace_stline(). */
6292__LJMP static int hlua_http_msg_set_query(lua_State *L)
6293{
6294 struct stream *s;
6295 struct http_msg *msg;
6296 const char *name;
6297 size_t name_len;
6298
6299 MAY_LJMP(check_args(L, 2, "set_query"));
6300 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6301 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6302
6303 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6304 WILL_LJMP(lua_error(L));
6305
6306 /* Check length. */
6307 if (name_len > trash.size - 1) {
6308 lua_pushboolean(L, 0);
6309 return 1;
6310 }
6311
6312 /* Add the mark question as prefix. */
6313 chunk_reset(&trash);
6314 trash.area[trash.data++] = '?';
6315 memcpy(trash.area + trash.data, name, name_len);
6316 trash.data += name_len;
6317
6318 s = chn_strm(msg->chn);
6319 lua_pushboolean(L, http_req_replace_stline(2, trash.area, trash.data, s->be, s) != -1);
6320 return 1;
6321}
6322
6323/* Rewrites the request URI. It relies on http_req_replace_stline(). */
6324__LJMP static int hlua_http_msg_set_uri(lua_State *L)
6325{
6326 struct stream *s;
6327 struct http_msg *msg;
6328 const char *name;
6329 size_t name_len;
6330
6331 MAY_LJMP(check_args(L, 2, "set_uri"));
6332 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6333 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6334
6335 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6336 WILL_LJMP(lua_error(L));
6337
6338 s = chn_strm(msg->chn);
6339 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, s->be, s) != -1);
6340 return 1;
6341}
6342
6343/* Rewrites the response status code. It relies on http_res_set_status(). */
6344__LJMP static int hlua_http_msg_set_status(lua_State *L)
6345{
6346 struct http_msg *msg;
6347 unsigned int code;
6348 const char *reason;
6349 size_t reason_len;
6350
6351 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6352 code = MAY_LJMP(luaL_checkinteger(L, 2));
6353 reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, &reason_len));
6354
6355 if (!(msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6356 WILL_LJMP(lua_error(L));
6357
6358 lua_pushboolean(L, http_res_set_status(code, ist2(reason, reason_len), chn_strm(msg->chn)) != -1);
6359 return 1;
6360}
6361
6362/* Returns true if the HTTP message is full. */
6363__LJMP static int hlua_http_msg_is_full(lua_State *L)
6364{
6365 struct http_msg *msg;
6366
6367 MAY_LJMP(check_args(L, 1, "is_full"));
6368 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6369 lua_pushboolean(L, channel_full(msg->chn, 0));
6370 return 1;
6371}
6372
6373/* Returns true if the HTTP message may still receive data. */
6374__LJMP static int hlua_http_msg_may_recv(lua_State *L)
6375{
6376 struct http_msg *msg;
6377 struct htx *htx;
6378
6379 MAY_LJMP(check_args(L, 1, "may_recv"));
6380 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6381 htx = htxbuf(&msg->chn->buf);
6382 lua_pushboolean(L, (htx_expect_more(htx) && !channel_input_closed(msg->chn) && channel_may_recv(msg->chn)));
6383 return 1;
6384}
6385
6386/* Returns true if the HTTP message EOM was received */
6387__LJMP static int hlua_http_msg_is_eom(lua_State *L)
6388{
6389 struct http_msg *msg;
6390 struct htx *htx;
6391
6392 MAY_LJMP(check_args(L, 1, "may_recv"));
6393 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6394 htx = htxbuf(&msg->chn->buf);
6395 lua_pushboolean(L, !htx_expect_more(htx));
6396 return 1;
6397}
6398
6399/* Returns the number of bytes available in the input side of the HTTP
6400 * message. This function never fails.
6401 */
6402__LJMP static int hlua_http_msg_get_in_len(lua_State *L)
6403{
6404 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006405 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006406
6407 MAY_LJMP(check_args(L, 1, "input"));
6408 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006409 hlua_http_msg_filter(L, 1, msg, &output, &input);
6410 lua_pushinteger(L, input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006411 return 1;
6412}
6413
6414/* Returns the number of bytes available in the output side of the HTTP
6415 * message. This function never fails.
6416 */
6417__LJMP static int hlua_http_msg_get_out_len(lua_State *L)
6418{
6419 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006420 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006421
6422 MAY_LJMP(check_args(L, 1, "output"));
6423 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006424 hlua_http_msg_filter(L, 1, msg, &output, &input);
6425 lua_pushinteger(L, output);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006426 return 1;
6427}
6428
6429/* Copies at most <len> bytes of DATA blocks from the HTTP message <msg>
6430 * starting at the offset <offset> and put it in a string LUA variables. It
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006431 * returns the built string length. It stops on the first non-DATA HTX
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006432 * block. This function is called during the payload filtering, so the headers
6433 * are already scheduled for output (from the filter point of view).
6434 */
6435static int _hlua_http_msg_dup(struct http_msg *msg, lua_State *L, size_t offset, size_t len)
6436{
6437 struct htx *htx = htxbuf(&msg->chn->buf);
6438 struct htx_blk *blk;
6439 struct htx_ret htxret;
6440 luaL_Buffer b;
6441 int ret = 0;
6442
6443 luaL_buffinit(L, &b);
6444 htxret = htx_find_offset(htx, offset);
6445 for (blk = htxret.blk, offset = htxret.ret; blk && len; blk = htx_get_next_blk(htx, blk)) {
6446 enum htx_blk_type type = htx_get_blk_type(blk);
6447 struct ist v;
6448
6449 switch (type) {
6450 case HTX_BLK_UNUSED:
6451 break;
6452
6453 case HTX_BLK_DATA:
6454 v = htx_get_blk_value(htx, blk);
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006455 v = istadv(v, offset);
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006456 v = isttrim(v, len);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006457
6458 luaL_addlstring(&b, v.ptr, v.len);
6459 ret += v.len;
6460 break;
6461
6462 default:
vishnu0af4bd72021-10-24 06:46:24 +05306463 if (!ret)
6464 goto no_data;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006465 goto end;
6466 }
6467 offset = 0;
6468 }
6469
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006470end:
vishnu0af4bd72021-10-24 06:46:24 +05306471 if (!ret && (htx->flags & HTX_FL_EOM))
6472 goto no_data;
6473 luaL_pushresult(&b);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006474 return ret;
vishnu0af4bd72021-10-24 06:46:24 +05306475
6476 no_data:
6477 /* Remove the empty string and push nil on the stack */
6478 lua_pop(L, 1);
6479 lua_pushnil(L);
6480 return 0;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006481}
6482
6483/* Copies the string <str> to the HTTP message <msg> at the offset
6484 * <offset>. This function returns -1 if data cannot be copied. Otherwise, it
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006485 * returns the amount of data written. This function is responsible to update
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006486 * the filter context.
6487 */
6488static int _hlua_http_msg_insert(struct http_msg *msg, struct filter *filter, struct ist str, size_t offset)
6489{
6490 struct htx *htx = htx_from_buf(&msg->chn->buf);
6491 struct htx_ret htxret;
6492 int /*max, */ret = 0;
6493
6494 /* Nothing to do, just return */
6495 if (unlikely(istlen(str) == 0))
6496 goto end;
6497
6498 if (istlen(str) > htx_free_data_space(htx)) {
6499 ret = -1;
6500 goto end;
6501 }
6502
6503 htxret = htx_find_offset(htx, offset);
6504 if (!htxret.blk || htx_get_blk_type(htxret.blk) != HTX_BLK_DATA) {
6505 if (!htx_add_last_data(htx, str))
6506 goto end;
6507 }
6508 else {
6509 struct ist v = htx_get_blk_value(htx, htxret.blk);
6510 v.ptr += htxret.ret;
6511 v.len = 0;
6512 if (!htx_replace_blk_value(htx, htxret.blk, v, str))
6513 goto end;
6514 }
6515 ret = str.len;
6516 if (ret) {
6517 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6518 flt_update_offsets(filter, msg->chn, ret);
6519 flt_ctx->cur_len[CHN_IDX(msg->chn)] += ret;
6520 }
6521
6522 end:
6523 htx_to_buf(htx, &msg->chn->buf);
6524 return ret;
6525}
6526
6527/* Helper function removing at most <len> bytes of DATA blocks at the absolute
6528 * position <offset>. It stops on the first non-DATA HTX block. This function is
6529 * called during the payload filtering, so the headers are already scheduled for
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006530 * output (from the filter point of view). This function is responsible to
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006531 * update the filter context.
6532 */
6533static void _hlua_http_msg_delete(struct http_msg *msg, struct filter *filter, size_t offset, size_t len)
6534{
6535 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6536 struct htx *htx = htx_from_buf(&msg->chn->buf);
6537 struct htx_blk *blk;
6538 struct htx_ret htxret;
6539 size_t ret = 0;
6540
6541 /* Be sure <len> is always the amount of DATA to remove */
6542 if (htx->data == offset+len && htx_get_tail_type(htx) == HTX_BLK_DATA) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006543 /* When htx tail type == HTX_BLK_DATA, no need to take care
6544 * of special blocks like HTX_BLK_EOT.
6545 * We simply truncate after offset
6546 * (truncate targeted blk and discard the following ones)
6547 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006548 htx_truncate(htx, offset);
6549 ret = len;
6550 goto end;
6551 }
6552
6553 htxret = htx_find_offset(htx, offset);
6554 blk = htxret.blk;
6555 if (htxret.ret) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006556 /* dealing with offset: we need to trim targeted blk */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006557 struct ist v;
6558
6559 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
6560 goto end;
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006561
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006562 v = htx_get_blk_value(htx, blk);
Tim Duesterhusa029d782022-10-08 12:33:18 +02006563 v = istadv(v, htxret.ret);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006564
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006565 v = isttrim(v, len);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006566 /* trimming data in blk: discard everything after the offset
6567 * (replace 'v' with 'IST_NULL')
6568 */
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006569 blk = htx_replace_blk_value(htx, blk, v, IST_NULL);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006570 if (blk && v.len < len) {
6571 /* In this case, caller wants to keep removing data,
6572 * but we need to spare current blk
6573 * because it was already trimmed
6574 */
6575 blk = htx_get_next_blk(htx, blk);
6576 }
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006577 len -= v.len;
6578 ret += v.len;
6579 }
6580
6581
6582 while (blk && len) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006583 /* there is more data that needs to be discarded */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006584 enum htx_blk_type type = htx_get_blk_type(blk);
6585 uint32_t sz = htx_get_blksz(blk);
6586
6587 switch (type) {
6588 case HTX_BLK_UNUSED:
6589 break;
6590
6591 case HTX_BLK_DATA:
6592 if (len < sz) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006593 /* don't discard whole blk, only part of it
6594 * (from the beginning)
6595 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006596 htx_cut_data_blk(htx, blk, len);
6597 ret += len;
6598 goto end;
6599 }
6600 break;
6601
6602 default:
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006603 /* HTX_BLK_EOT blk won't be removed */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006604 goto end;
6605 }
6606
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006607 /* Remove all the data block */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006608 len -= sz;
6609 ret += sz;
6610 blk = htx_remove_blk(htx, blk);
6611 }
6612
6613end:
6614 flt_update_offsets(filter, msg->chn, -ret);
6615 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
6616 /* WARNING: we don't call htx_to_buf() on purpose, because we don't want
6617 * to loose the EOM flag if the message is empty.
6618 */
6619}
6620
6621/* Copies input data found in an HTTP message. Unlike the channel function used
6622 * to duplicate raw data, this one can only be called inside a filter, from
6623 * http_payload callback. So it cannot yield. An exception is returned if it is
6624 * called from another callback. If nothing was copied, a nil value is pushed on
6625 * the stack.
6626 */
6627__LJMP static int hlua_http_msg_get_body(lua_State *L)
6628{
6629 struct http_msg *msg;
6630 struct filter *filter;
6631 size_t output, input;
6632 int offset, len;
6633
6634 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
6635 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
6636 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6637
6638 if (msg->msg_state < HTTP_MSG_DATA)
6639 WILL_LJMP(lua_error(L));
6640
6641 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6642 if (!filter || !hlua_filter_from_payload(filter))
6643 WILL_LJMP(lua_error(L));
6644
6645 if (!ci_data(msg->chn) && channel_input_closed(msg->chn)) {
6646 lua_pushnil(L);
6647 return 1;
6648 }
6649
6650 offset = output;
6651 if (lua_gettop(L) > 1) {
6652 offset = MAY_LJMP(luaL_checkinteger(L, 2));
6653 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006654 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006655 offset += output;
6656 if (offset < output || offset > input + output) {
6657 lua_pushfstring(L, "offset out of range.");
6658 WILL_LJMP(lua_error(L));
6659 }
6660 }
6661 len = output + input - offset;
6662 if (lua_gettop(L) == 3) {
6663 len = MAY_LJMP(luaL_checkinteger(L, 3));
6664 if (!len)
6665 goto dup;
6666 if (len == -1)
6667 len = global.tune.bufsize;
6668 if (len < 0) {
6669 lua_pushfstring(L, "length out of range.");
6670 WILL_LJMP(lua_error(L));
6671 }
6672 }
6673
6674 dup:
6675 _hlua_http_msg_dup(msg, L, offset, len);
6676 return 1;
6677}
6678
6679/* Appends a string to the HTTP message, after all existing DATA blocks but
6680 * before the trailers, if any. It returns the amount of data written or -1 if
6681 * nothing was copied. Unlike the channel function used to append data, this one
6682 * can only be called inside a filter, from http_payload callback. So it cannot
6683 * yield. An exception is returned if it is called from another callback.
6684 */
6685__LJMP static int hlua_http_msg_append(lua_State *L)
6686{
6687 struct http_msg *msg;
6688 struct filter *filter;
6689 const char *str;
6690 size_t offset, len, sz;
6691 int ret;
6692
6693 MAY_LJMP(check_args(L, 2, "append"));
6694 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6695
6696 if (msg->msg_state < HTTP_MSG_DATA)
6697 WILL_LJMP(lua_error(L));
6698
6699 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6700 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6701 if (!filter || !hlua_filter_from_payload(filter))
6702 WILL_LJMP(lua_error(L));
6703
6704 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset+len);
6705 lua_pushinteger(L, ret);
6706 return 1;
6707}
6708
6709/* Prepends a string to the HTTP message, before all existing DATA blocks. It
6710 * returns the amount of data written or -1 if nothing was copied. Unlike the
6711 * channel function used to prepend data, this one can only be called inside a
6712 * filter, from http_payload callback. So it cannot yield. An exception is
6713 * returned if it is called from another callback.
6714 */
6715__LJMP static int hlua_http_msg_prepend(lua_State *L)
6716{
6717 struct http_msg *msg;
6718 struct filter *filter;
6719 const char *str;
6720 size_t offset, len, sz;
6721 int ret;
6722
6723 MAY_LJMP(check_args(L, 2, "prepend"));
6724 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006725
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006726 if (msg->msg_state < HTTP_MSG_DATA)
6727 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006728
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006729 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6730 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6731 if (!filter || !hlua_filter_from_payload(filter))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006732 WILL_LJMP(lua_error(L));
6733
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006734 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6735 lua_pushinteger(L, ret);
6736 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006737}
6738
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006739/* Inserts a string to the HTTP message at a given offset. By default the string
6740 * is appended at the end of DATA blocks. It returns the amount of data written
6741 * or -1 if nothing was copied. Unlike the channel function used to insert data,
6742 * this one can only be called inside a filter, from http_payload callback. So
6743 * it cannot yield. An exception is returned if it is called from another
6744 * callback.
6745 */
6746__LJMP static int hlua_http_msg_insert_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006747{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006748 struct http_msg *msg;
6749 struct filter *filter;
6750 const char *str;
6751 size_t input, output, sz;
6752 int offset;
6753 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006754
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006755 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
6756 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006757 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006758
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006759 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006760 WILL_LJMP(lua_error(L));
6761
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006762 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006763 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006764 if (!filter || !hlua_filter_from_payload(filter))
6765 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006766
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006767 offset = output;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006768 if (lua_gettop(L) > 2) {
6769 offset = MAY_LJMP(luaL_checkinteger(L, 3));
6770 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006771 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006772 offset += output;
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006773 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006774 lua_pushfstring(L, "offset out of range.");
6775 WILL_LJMP(lua_error(L));
6776 }
6777 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006778
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006779 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6780 lua_pushinteger(L, ret);
6781 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006782}
6783
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006784/* Removes a given amount of data from the HTTP message at a given offset. By
6785 * default all DATA blocks are removed. It returns the amount of data
6786 * removed. Unlike the channel function used to remove data, this one can only
6787 * be called inside a filter, from http_payload callback. So it cannot yield. An
6788 * exception is returned if it is called from another callback.
6789 */
6790__LJMP static int hlua_http_msg_del_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006791{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006792 struct http_msg *msg;
6793 struct filter *filter;
6794 size_t input, output;
6795 int offset, len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006796
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006797 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
Boyang Lie0c54352022-05-10 17:47:23 +00006798 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006799 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006800
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006801 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006802 WILL_LJMP(lua_error(L));
6803
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006804 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006805 if (!filter || !hlua_filter_from_payload(filter))
6806 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006807
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006808 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00006809 if (lua_gettop(L) > 1) {
6810 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006811 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006812 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006813 offset += output;
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006814 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006815 lua_pushfstring(L, "offset out of range.");
6816 WILL_LJMP(lua_error(L));
6817 }
6818 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006819
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006820 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00006821 if (lua_gettop(L) == 3) {
6822 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006823 if (!len)
6824 goto end;
6825 if (len == -1)
6826 len = output + input - offset;
6827 if (len < 0 || offset + len > output + input) {
6828 lua_pushfstring(L, "length out of range.");
6829 WILL_LJMP(lua_error(L));
6830 }
6831 }
6832
6833 _hlua_http_msg_delete(msg, filter, offset, len);
6834
6835 end:
6836 lua_pushinteger(L, len);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006837 return 1;
6838}
6839
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006840/* Replaces a given amount of data at the given offset by a string. By default,
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006841 * all remaining data are removed, accordingly to the filter context. It returns
6842 * the amount of data written or -1 if nothing was copied. Unlike the channel
6843 * function used to replace data, this one can only be called inside a filter,
6844 * from http_payload callback. So it cannot yield. An exception is returned if
6845 * it is called from another callback.
6846 */
6847__LJMP static int hlua_http_msg_set_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006848{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006849 struct http_msg *msg;
6850 struct filter *filter;
6851 struct htx *htx;
6852 const char *str;
6853 size_t input, output, sz;
6854 int offset, len;
6855 int ret;
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02006856
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006857 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
6858 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
6859 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6860
6861 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006862 WILL_LJMP(lua_error(L));
6863
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006864 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6865 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6866 if (!filter || !hlua_filter_from_payload(filter))
6867 WILL_LJMP(lua_error(L));
6868
6869 offset = output;
6870 if (lua_gettop(L) > 2) {
6871 offset = MAY_LJMP(luaL_checkinteger(L, 3));
6872 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006873 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006874 offset += output;
6875 if (offset < output || offset > input + output) {
6876 lua_pushfstring(L, "offset out of range.");
6877 WILL_LJMP(lua_error(L));
6878 }
6879 }
6880
6881 len = output + input - offset;
6882 if (lua_gettop(L) == 4) {
6883 len = MAY_LJMP(luaL_checkinteger(L, 4));
6884 if (!len)
6885 goto set;
6886 if (len == -1)
6887 len = output + input - offset;
6888 if (len < 0 || offset + len > output + input) {
6889 lua_pushfstring(L, "length out of range.");
6890 WILL_LJMP(lua_error(L));
6891 }
6892 }
6893
6894 set:
6895 /* Be sure we can copied the string once input data will be removed. */
6896 htx = htx_from_buf(&msg->chn->buf);
6897 if (sz > htx_free_data_space(htx) + len)
6898 lua_pushinteger(L, -1);
6899 else {
6900 _hlua_http_msg_delete(msg, filter, offset, len);
6901 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6902 lua_pushinteger(L, ret);
6903 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006904 return 1;
6905}
6906
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006907/* Prepends data into an HTTP message and forward it, from the filter point of
6908 * view. It returns the amount of data written or -1 if nothing was sent. Unlike
6909 * the channel function used to send data, this one can only be called inside a
6910 * filter, from http_payload callback. So it cannot yield. An exception is
6911 * returned if it is called from another callback.
6912 */
6913__LJMP static int hlua_http_msg_send(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006914{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006915 struct http_msg *msg;
6916 struct filter *filter;
6917 struct htx *htx;
6918 const char *str;
6919 size_t offset, len, sz;
6920 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006921
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006922 MAY_LJMP(check_args(L, 2, "send"));
6923 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6924
6925 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006926 WILL_LJMP(lua_error(L));
6927
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006928 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6929 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6930 if (!filter || !hlua_filter_from_payload(filter))
6931 WILL_LJMP(lua_error(L));
6932
6933 /* Return an error if the channel's output is closed */
6934 if (unlikely(channel_output_closed(msg->chn))) {
6935 lua_pushinteger(L, -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006936 return 1;
6937 }
6938
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006939 htx = htx_from_buf(&msg->chn->buf);
6940 if (sz > htx_free_data_space(htx)) {
6941 lua_pushinteger(L, -1);
6942 return 1;
6943 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006944
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006945 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6946 if (ret > 0) {
6947 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6948
6949 FLT_OFF(filter, msg->chn) += ret;
6950 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
6951 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
6952 }
6953
6954 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006955 return 1;
6956}
6957
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006958/* Forwards a given amount of bytes. It return -1 if the channel's output is
6959 * closed. Otherwise, it returns the number of bytes forwarded. Unlike the
6960 * channel function used to forward data, this one can only be called inside a
6961 * filter, from http_payload callback. So it cannot yield. An exception is
6962 * returned if it is called from another callback. All other functions deal with
6963 * DATA block, this one not.
6964*/
6965__LJMP static int hlua_http_msg_forward(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006966{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006967 struct http_msg *msg;
6968 struct filter *filter;
6969 size_t offset, len;
6970 int fwd, ret = 0;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006971
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006972 MAY_LJMP(check_args(L, 2, "forward"));
6973 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6974
6975 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006976 WILL_LJMP(lua_error(L));
6977
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006978 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
6979 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6980 if (!filter || !hlua_filter_from_payload(filter))
6981 WILL_LJMP(lua_error(L));
6982
6983 /* Nothing to do, just return */
6984 if (!fwd)
6985 goto end;
6986
6987 /* Return an error if the channel's output is closed */
6988 if (unlikely(channel_output_closed(msg->chn))) {
6989 ret = -1;
6990 goto end;
6991 }
6992
6993 ret = fwd;
6994 if (ret > len)
6995 ret = len;
6996
6997 if (ret) {
6998 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6999
7000 FLT_OFF(filter, msg->chn) += ret;
7001 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
7002 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
7003 }
7004
7005 end:
7006 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007007 return 1;
7008}
7009
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007010/* Set EOM flag on the HTX message.
7011 *
7012 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7013 * really know how to do without this feature.
7014 */
7015__LJMP static int hlua_http_msg_set_eom(lua_State *L)
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007016{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007017 struct http_msg *msg;
7018 struct htx *htx;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007019
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007020 MAY_LJMP(check_args(L, 1, "set_eom"));
7021 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7022 htx = htxbuf(&msg->chn->buf);
7023 htx->flags |= HTX_FL_EOM;
7024 return 0;
7025}
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007026
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007027/* Unset EOM flag on the HTX message.
7028 *
7029 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7030 * really know how to do without this feature.
7031 */
7032__LJMP static int hlua_http_msg_unset_eom(lua_State *L)
7033{
7034 struct http_msg *msg;
7035 struct htx *htx;
7036
7037 MAY_LJMP(check_args(L, 1, "set_eom"));
7038 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7039 htx = htxbuf(&msg->chn->buf);
7040 htx->flags &= ~HTX_FL_EOM;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007041 return 0;
7042}
7043
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007044/*
7045 *
7046 *
William Lallemand3956c4e2021-09-21 16:25:15 +02007047 * Class HTTPClient
7048 *
7049 *
7050 */
7051__LJMP static struct hlua_httpclient *hlua_checkhttpclient(lua_State *L, int ud)
7052{
7053 return MAY_LJMP(hlua_checkudata(L, ud, class_httpclient_ref));
7054}
7055
William Lallemandf77f1de2021-09-28 19:10:38 +02007056
7057/* stops the httpclient and ask it to kill itself */
7058__LJMP static int hlua_httpclient_gc(lua_State *L)
7059{
7060 struct hlua_httpclient *hlua_hc;
7061
7062 MAY_LJMP(check_args(L, 1, "__gc"));
7063
7064 hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
7065
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007066 if (MT_LIST_DELETE(&hlua_hc->by_hlua)) {
7067 /* we won the race against hlua_httpclient_destroy_all() */
William Lallemandbb581422022-10-20 10:57:28 +02007068 httpclient_stop_and_destroy(hlua_hc->hc);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007069 hlua_hc->hc = NULL;
7070 }
William Lallemandf77f1de2021-09-28 19:10:38 +02007071
7072 return 0;
7073}
7074
7075
William Lallemand3956c4e2021-09-21 16:25:15 +02007076__LJMP static int hlua_httpclient_new(lua_State *L)
7077{
7078 struct hlua_httpclient *hlua_hc;
7079 struct hlua *hlua;
7080
7081 /* Get hlua struct, or NULL if we execute from main lua state */
7082 hlua = hlua_gethlua(L);
7083 if (!hlua)
7084 return 0;
7085
7086 /* Check stack size. */
7087 if (!lua_checkstack(L, 3)) {
7088 hlua_pusherror(L, "httpclient: full stack");
7089 goto err;
7090 }
7091 /* Create the object: obj[0] = userdata. */
7092 lua_newtable(L);
7093 hlua_hc = MAY_LJMP(lua_newuserdata(L, sizeof(*hlua_hc)));
7094 lua_rawseti(L, -2, 0);
7095 memset(hlua_hc, 0, sizeof(*hlua_hc));
7096
7097 hlua_hc->hc = httpclient_new(hlua, 0, IST_NULL);
7098 if (!hlua_hc->hc)
7099 goto err;
7100
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007101 MT_LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
William Lallemandbb581422022-10-20 10:57:28 +02007102
William Lallemand3956c4e2021-09-21 16:25:15 +02007103 /* Pop a class stream metatable and affect it to the userdata. */
7104 lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
7105 lua_setmetatable(L, -2);
7106
7107 return 1;
7108
7109 err:
7110 WILL_LJMP(lua_error(L));
7111 return 0;
7112}
7113
7114
7115/*
7116 * Callback of the httpclient, this callback wakes the lua task up, once the
7117 * httpclient receives some data
7118 *
7119 */
7120
William Lallemandbd5739e2021-10-28 15:41:38 +02007121static void hlua_httpclient_cb(struct httpclient *hc)
William Lallemand3956c4e2021-09-21 16:25:15 +02007122{
7123 struct hlua *hlua = hc->caller;
7124
7125 if (!hlua || !hlua->task)
7126 return;
7127
7128 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7129}
7130
7131/*
William Lallemandd7df73a2021-09-23 17:54:00 +02007132 * Fill the lua stack with headers from the httpclient response
7133 * This works the same way as the hlua_http_get_headers() function
7134 */
7135__LJMP static int hlua_httpclient_get_headers(lua_State *L, struct hlua_httpclient *hlua_hc)
7136{
7137 struct http_hdr *hdr;
7138
7139 lua_newtable(L);
7140
William Lallemandef574b22021-10-05 16:19:31 +02007141 for (hdr = hlua_hc->hc->res.hdrs; hdr && isttest(hdr->n); hdr++) {
William Lallemandd7df73a2021-09-23 17:54:00 +02007142 struct ist n, v;
7143 int len;
7144
7145 n = hdr->n;
7146 v = hdr->v;
7147
7148 /* Check for existing entry:
7149 * assume that the table is on the top of the stack, and
7150 * push the key in the stack, the function lua_gettable()
7151 * perform the lookup.
7152 */
7153
7154 lua_pushlstring(L, n.ptr, n.len);
7155 lua_gettable(L, -2);
7156
7157 switch (lua_type(L, -1)) {
7158 case LUA_TNIL:
7159 /* Table not found, create it. */
7160 lua_pop(L, 1); /* remove the nil value. */
7161 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
7162 lua_newtable(L); /* create and push empty table. */
7163 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7164 lua_rawseti(L, -2, 0); /* index header value (pop it). */
7165 lua_rawset(L, -3); /* index new table with header name (pop the values). */
7166 break;
7167
7168 case LUA_TTABLE:
7169 /* Entry found: push the value in the table. */
7170 len = lua_rawlen(L, -1);
7171 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7172 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
7173 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
7174 break;
7175
7176 default:
7177 /* Other cases are errors. */
7178 hlua_pusherror(L, "internal error during the parsing of headers.");
7179 WILL_LJMP(lua_error(L));
7180 }
7181 }
7182 return 1;
7183}
7184
7185/*
William Lallemand746e6f32021-10-06 10:57:44 +02007186 * Allocate and return an array of http_hdr ist extracted from the <headers> lua table
7187 *
7188 * Caller must free the result
7189 */
7190struct http_hdr *hlua_httpclient_table_to_hdrs(lua_State *L)
7191{
7192 struct http_hdr hdrs[global.tune.max_http_hdr];
7193 struct http_hdr *result = NULL;
7194 uint32_t hdr_num = 0;
7195
7196 lua_pushnil(L);
7197 while (lua_next(L, -2) != 0) {
7198 struct ist name, value;
7199 const char *n, *v;
7200 size_t nlen, vlen;
7201
7202 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
7203 /* Skip element if the key is not a string or if the value is not a table */
7204 goto next_hdr;
7205 }
7206
7207 n = lua_tolstring(L, -2, &nlen);
7208 name = ist2(n, nlen);
7209
7210 /* Loop on header's values */
7211 lua_pushnil(L);
7212 while (lua_next(L, -2)) {
7213 if (!lua_isstring(L, -1)) {
7214 /* Skip the value if it is not a string */
7215 goto next_value;
7216 }
7217
7218 v = lua_tolstring(L, -1, &vlen);
7219 value = ist2(v, vlen);
7220 name = ist2(n, nlen);
7221
7222 hdrs[hdr_num].n = istdup(name);
7223 hdrs[hdr_num].v = istdup(value);
7224
7225 hdr_num++;
7226
7227 next_value:
7228 lua_pop(L, 1);
7229 }
7230
7231 next_hdr:
7232 lua_pop(L, 1);
7233
7234 }
7235
7236 if (hdr_num) {
7237 /* alloc and copy the headers in the httpclient struct */
Tim Duesterhus16cc16d2021-11-06 15:14:45 +01007238 result = calloc((hdr_num + 1), sizeof(*result));
William Lallemand746e6f32021-10-06 10:57:44 +02007239 if (!result)
7240 goto skip_headers;
7241 memcpy(result, hdrs, sizeof(struct http_hdr) * (hdr_num + 1));
7242
7243 result[hdr_num].n = IST_NULL;
7244 result[hdr_num].v = IST_NULL;
7245 }
7246
7247skip_headers:
William Lallemand746e6f32021-10-06 10:57:44 +02007248
7249 return result;
7250}
7251
7252
William Lallemandbd5739e2021-10-28 15:41:38 +02007253/*
7254 * For each yield, checks if there is some data in the httpclient and push them
7255 * in the lua buffer, once the httpclient finished its job, push the result on
7256 * the stack
7257 */
7258__LJMP static int hlua_httpclient_rcv_yield(lua_State *L, int status, lua_KContext ctx)
7259{
7260 struct buffer *tr;
7261 int res;
7262 struct hlua *hlua = hlua_gethlua(L);
7263 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7264
7265
7266 tr = get_trash_chunk();
7267
7268 res = httpclient_res_xfer(hlua_hc->hc, tr);
7269 luaL_addlstring(&hlua_hc->b, b_orig(tr), res);
7270
7271 if (!httpclient_data(hlua_hc->hc) && httpclient_ended(hlua_hc->hc)) {
7272
7273 luaL_pushresult(&hlua_hc->b);
7274 lua_settable(L, -3);
7275
7276 lua_pushstring(L, "status");
7277 lua_pushinteger(L, hlua_hc->hc->res.status);
7278 lua_settable(L, -3);
7279
7280
7281 lua_pushstring(L, "reason");
7282 lua_pushlstring(L, hlua_hc->hc->res.reason.ptr, hlua_hc->hc->res.reason.len);
7283 lua_settable(L, -3);
7284
7285 lua_pushstring(L, "headers");
7286 hlua_httpclient_get_headers(L, hlua_hc);
7287 lua_settable(L, -3);
7288
7289 return 1;
7290 }
7291
7292 if (httpclient_data(hlua_hc->hc))
7293 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7294
7295 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7296
7297 return 0;
7298}
7299
7300/*
7301 * Call this when trying to stream a body during a request
7302 */
7303__LJMP static int hlua_httpclient_snd_yield(lua_State *L, int status, lua_KContext ctx)
7304{
7305 struct hlua *hlua;
7306 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7307 const char *body_str = NULL;
7308 int ret;
7309 int end = 0;
7310 size_t buf_len;
7311 size_t to_send = 0;
7312
7313 hlua = hlua_gethlua(L);
7314
7315 if (!hlua || !hlua->task)
7316 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7317 "'frontend', 'backend' or 'task'"));
7318
7319 ret = lua_getfield(L, -1, "body");
7320 if (ret != LUA_TSTRING)
7321 goto rcv;
7322
7323 body_str = lua_tolstring(L, -1, &buf_len);
7324 lua_pop(L, 1);
7325
Christopher Fauletfc591292022-01-12 14:46:03 +01007326 to_send = buf_len - hlua_hc->sent;
William Lallemandbd5739e2021-10-28 15:41:38 +02007327
7328 if ((hlua_hc->sent + to_send) >= buf_len)
7329 end = 1;
7330
7331 /* the end flag is always set since we are using the whole remaining size */
7332 hlua_hc->sent += httpclient_req_xfer(hlua_hc->hc, ist2(body_str + hlua_hc->sent, to_send), end);
7333
7334 if (buf_len > hlua_hc->sent) {
7335 /* still need to process the buffer */
7336 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
7337 } else {
7338 goto rcv;
7339 /* we sent the whole request buffer we can recv */
7340 }
7341 return 0;
7342
7343rcv:
7344
7345 /* we return a "res" object */
7346 lua_newtable(L);
7347
William Lallemandbd5739e2021-10-28 15:41:38 +02007348 lua_pushstring(L, "body");
William Lallemandd1187eb2021-11-02 10:40:06 +01007349 luaL_buffinit(L, &hlua_hc->b);
William Lallemandbd5739e2021-10-28 15:41:38 +02007350
William Lallemand933fe392021-11-04 09:45:58 +01007351 task_wakeup(hlua->task, TASK_WOKEN_MSG);
William Lallemandbd5739e2021-10-28 15:41:38 +02007352 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7353
7354 return 1;
7355}
William Lallemand746e6f32021-10-06 10:57:44 +02007356
William Lallemand3956c4e2021-09-21 16:25:15 +02007357/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007358 * Send an HTTP request and wait for a response
William Lallemand3956c4e2021-09-21 16:25:15 +02007359 */
7360
William Lallemanddc2cc902021-10-26 11:43:26 +02007361__LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
William Lallemand3956c4e2021-09-21 16:25:15 +02007362{
7363 struct hlua_httpclient *hlua_hc;
William Lallemand746e6f32021-10-06 10:57:44 +02007364 struct http_hdr *hdrs = NULL;
7365 struct http_hdr *hdrs_i = NULL;
William Lallemand3956c4e2021-09-21 16:25:15 +02007366 struct hlua *hlua;
William Lallemand746e6f32021-10-06 10:57:44 +02007367 const char *url_str = NULL;
William Lallemanddec25c32021-10-25 19:48:37 +02007368 const char *body_str = NULL;
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007369 size_t buf_len = 0;
William Lallemand746e6f32021-10-06 10:57:44 +02007370 int ret;
William Lallemand3956c4e2021-09-21 16:25:15 +02007371
7372 hlua = hlua_gethlua(L);
7373
7374 if (!hlua || !hlua->task)
7375 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7376 "'frontend', 'backend' or 'task'"));
7377
William Lallemand746e6f32021-10-06 10:57:44 +02007378 if (lua_gettop(L) != 2 || lua_type(L, -1) != LUA_TTABLE)
7379 WILL_LJMP(luaL_error(L, "'get' needs a table as argument"));
7380
William Lallemand4f4f2b72022-02-17 20:00:23 +01007381 hlua_hc = hlua_checkhttpclient(L, 1);
7382
William Lallemand7177a952022-03-03 15:33:12 +01007383 lua_pushnil(L); /* first key */
7384 while (lua_next(L, 2)) {
7385 if (strcmp(lua_tostring(L, -2), "dst") == 0) {
7386 if (httpclient_set_dst(hlua_hc->hc, lua_tostring(L, -1)) < 0)
7387 WILL_LJMP(luaL_error(L, "Can't use the 'dst' argument"));
William Lallemand4f4f2b72022-02-17 20:00:23 +01007388
William Lallemand7177a952022-03-03 15:33:12 +01007389 } else if (strcmp(lua_tostring(L, -2), "url") == 0) {
7390 if (lua_type(L, -1) != LUA_TSTRING)
7391 WILL_LJMP(luaL_error(L, "invalid parameter in 'url', must be a string"));
7392 url_str = lua_tostring(L, -1);
William Lallemand3956c4e2021-09-21 16:25:15 +02007393
William Lallemand7177a952022-03-03 15:33:12 +01007394 } else if (strcmp(lua_tostring(L, -2), "timeout") == 0) {
7395 if (lua_type(L, -1) != LUA_TNUMBER)
7396 WILL_LJMP(luaL_error(L, "invalid parameter in 'timeout', must be a number"));
7397 httpclient_set_timeout(hlua_hc->hc, lua_tointeger(L, -1));
William Lallemandb4a4ef62022-02-23 14:18:16 +01007398
William Lallemand7177a952022-03-03 15:33:12 +01007399 } else if (strcmp(lua_tostring(L, -2), "headers") == 0) {
7400 if (lua_type(L, -1) != LUA_TTABLE)
7401 WILL_LJMP(luaL_error(L, "invalid parameter in 'headers', must be a table"));
7402 hdrs = hlua_httpclient_table_to_hdrs(L);
William Lallemand79416cb2021-09-24 14:51:44 +02007403
William Lallemand7177a952022-03-03 15:33:12 +01007404 } else if (strcmp(lua_tostring(L, -2), "body") == 0) {
7405 if (lua_type(L, -1) != LUA_TSTRING)
7406 WILL_LJMP(luaL_error(L, "invalid parameter in 'body', must be a string"));
7407 body_str = lua_tolstring(L, -1, &buf_len);
William Lallemandbd5739e2021-10-28 15:41:38 +02007408
William Lallemand7177a952022-03-03 15:33:12 +01007409 } else {
7410 WILL_LJMP(luaL_error(L, "'%s' invalid parameter name", lua_tostring(L, -2)));
7411 }
7412 /* removes 'value'; keeps 'key' for next iteration */
7413 lua_pop(L, 1);
7414 }
William Lallemanddec25c32021-10-25 19:48:37 +02007415
William Lallemand746e6f32021-10-06 10:57:44 +02007416 if (!url_str) {
7417 WILL_LJMP(luaL_error(L, "'get' need a 'url' argument"));
7418 return 0;
7419 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007420
William Lallemand10a37362022-03-02 16:18:26 +01007421 hlua_hc->sent = 0;
William Lallemand3956c4e2021-09-21 16:25:15 +02007422
Aurelien DARRAGON03564072023-02-09 15:26:25 +01007423 istfree(&hlua_hc->hc->req.url);
William Lallemand3956c4e2021-09-21 16:25:15 +02007424 hlua_hc->hc->req.url = istdup(ist(url_str));
William Lallemanddc2cc902021-10-26 11:43:26 +02007425 hlua_hc->hc->req.meth = meth;
William Lallemand3956c4e2021-09-21 16:25:15 +02007426
7427 /* update the httpclient callbacks */
William Lallemandbd5739e2021-10-28 15:41:38 +02007428 hlua_hc->hc->ops.res_stline = hlua_httpclient_cb;
7429 hlua_hc->hc->ops.res_headers = hlua_httpclient_cb;
7430 hlua_hc->hc->ops.res_payload = hlua_httpclient_cb;
William Lallemand8f170c72022-03-15 10:52:07 +01007431 hlua_hc->hc->ops.res_end = hlua_httpclient_cb;
William Lallemand3956c4e2021-09-21 16:25:15 +02007432
William Lallemandbd5739e2021-10-28 15:41:38 +02007433 /* a body is available, it will use the request callback */
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007434 if (body_str && buf_len) {
William Lallemandbd5739e2021-10-28 15:41:38 +02007435 hlua_hc->hc->ops.req_payload = hlua_httpclient_cb;
7436 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007437
William Lallemandbd5739e2021-10-28 15:41:38 +02007438 ret = httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, meth, hdrs, IST_NULL);
William Lallemand3956c4e2021-09-21 16:25:15 +02007439
William Lallemand746e6f32021-10-06 10:57:44 +02007440 /* free the temporary headers array */
7441 hdrs_i = hdrs;
7442 while (hdrs_i && isttest(hdrs_i->n)) {
7443 istfree(&hdrs_i->n);
7444 istfree(&hdrs_i->v);
7445 hdrs_i++;
7446 }
7447 ha_free(&hdrs);
7448
7449
William Lallemand6137a9e2021-10-26 15:01:53 +02007450 if (ret != ERR_NONE) {
7451 WILL_LJMP(luaL_error(L, "Can't generate the HTTP request"));
7452 return 0;
7453 }
7454
William Lallemandc2d3db42022-04-26 11:46:13 +02007455 if (!httpclient_start(hlua_hc->hc))
7456 WILL_LJMP(luaL_error(L, "couldn't start the httpclient"));
William Lallemand6137a9e2021-10-26 15:01:53 +02007457
William Lallemandbd5739e2021-10-28 15:41:38 +02007458 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
William Lallemand3956c4e2021-09-21 16:25:15 +02007459
William Lallemand3956c4e2021-09-21 16:25:15 +02007460 return 0;
7461}
7462
7463/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007464 * Sends an HTTP HEAD request and wait for a response
7465 *
7466 * httpclient:head(url, headers, payload)
7467 */
7468__LJMP static int hlua_httpclient_head(lua_State *L)
7469{
7470 return hlua_httpclient_send(L, HTTP_METH_HEAD);
7471}
7472
7473/*
7474 * Send an HTTP GET request and wait for a response
7475 *
7476 * httpclient:get(url, headers, payload)
7477 */
7478__LJMP static int hlua_httpclient_get(lua_State *L)
7479{
7480 return hlua_httpclient_send(L, HTTP_METH_GET);
7481
7482}
7483
7484/*
7485 * Sends an HTTP PUT request and wait for a response
7486 *
7487 * httpclient:put(url, headers, payload)
7488 */
7489__LJMP static int hlua_httpclient_put(lua_State *L)
7490{
7491 return hlua_httpclient_send(L, HTTP_METH_PUT);
7492}
7493
7494/*
7495 * Send an HTTP POST request and wait for a response
7496 *
7497 * httpclient:post(url, headers, payload)
7498 */
7499__LJMP static int hlua_httpclient_post(lua_State *L)
7500{
7501 return hlua_httpclient_send(L, HTTP_METH_POST);
7502}
7503
7504
7505/*
7506 * Sends an HTTP DELETE request and wait for a response
7507 *
7508 * httpclient:delete(url, headers, payload)
7509 */
7510__LJMP static int hlua_httpclient_delete(lua_State *L)
7511{
7512 return hlua_httpclient_send(L, HTTP_METH_DELETE);
7513}
7514
7515/*
William Lallemand3956c4e2021-09-21 16:25:15 +02007516 *
7517 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007518 * Class TXN
7519 *
7520 *
7521 */
7522
7523/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02007524 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007525 */
7526__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
7527{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007528 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007529}
7530
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007531__LJMP static int hlua_set_var(lua_State *L)
7532{
7533 struct hlua_txn *htxn;
7534 const char *name;
7535 size_t len;
7536 struct sample smp;
7537
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007538 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7539 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007540
7541 /* It is useles to retrieve the stream, but this function
7542 * runs only in a stream context.
7543 */
7544 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7545 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7546
7547 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01007548 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007549 hlua_lua2smp(L, 3, &smp);
7550
7551 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01007552 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007553
7554 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
7555 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
7556 else
7557 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
7558
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007559 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007560}
7561
Christopher Faulet85d79c92016-11-09 16:54:56 +01007562__LJMP static int hlua_unset_var(lua_State *L)
7563{
7564 struct hlua_txn *htxn;
7565 const char *name;
7566 size_t len;
7567 struct sample smp;
7568
7569 MAY_LJMP(check_args(L, 2, "unset_var"));
7570
7571 /* It is useles to retrieve the stream, but this function
7572 * runs only in a stream context.
7573 */
7574 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7575 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7576
7577 /* Unset the variable. */
7578 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007579 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
7580 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01007581}
7582
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007583__LJMP static int hlua_get_var(lua_State *L)
7584{
7585 struct hlua_txn *htxn;
7586 const char *name;
7587 size_t len;
7588 struct sample smp;
7589
7590 MAY_LJMP(check_args(L, 2, "get_var"));
7591
7592 /* It is useles to retrieve the stream, but this function
7593 * runs only in a stream context.
7594 */
7595 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7596 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7597
Willy Tarreau7560dd42016-03-10 16:28:58 +01007598 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02007599 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007600 lua_pushnil(L);
7601 return 1;
7602 }
7603
7604 return hlua_smp2lua(L, &smp);
7605}
7606
Willy Tarreau59551662015-03-10 14:23:13 +01007607__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007608{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007609 struct hlua *hlua;
7610
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007611 MAY_LJMP(check_args(L, 2, "set_priv"));
7612
Willy Tarreau87b09662015-04-03 00:22:06 +02007613 /* It is useles to retrieve the stream, but this function
7614 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007615 */
7616 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007617
7618 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007619 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007620 if (!hlua)
7621 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007622
7623 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02007624 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007625
7626 /* Get and store new value. */
7627 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
7628 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
7629
7630 return 0;
7631}
7632
Willy Tarreau59551662015-03-10 14:23:13 +01007633__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007634{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007635 struct hlua *hlua;
7636
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007637 MAY_LJMP(check_args(L, 1, "get_priv"));
7638
Willy Tarreau87b09662015-04-03 00:22:06 +02007639 /* It is useles to retrieve the stream, but this function
7640 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007641 */
7642 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007643
7644 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007645 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007646 if (!hlua) {
7647 lua_pushnil(L);
7648 return 1;
7649 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007650
7651 /* Push configuration index in the stack. */
7652 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
7653
7654 return 1;
7655}
7656
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007657/* Create stack entry containing a class TXN. This function
7658 * return 0 if the stack does not contains free slots,
7659 * otherwise it returns 1.
7660 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007661static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007662{
Willy Tarreaude491382015-04-06 11:04:28 +02007663 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007664
7665 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007666 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007667 return 0;
7668
7669 /* NOTE: The allocation never fails. The failure
7670 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007671 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007672 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007673 /* Create the object: obj[0] = userdata. */
7674 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02007675 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007676 lua_rawseti(L, -2, 0);
7677
Willy Tarreaude491382015-04-06 11:04:28 +02007678 htxn->s = s;
7679 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01007680 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007681 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007682
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007683 /* Create the "f" field that contains a list of fetches. */
7684 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007685 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007686 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007687 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007688
7689 /* Create the "sf" field that contains a list of stringsafe fetches. */
7690 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007691 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007692 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007693 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007694
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007695 /* Create the "c" field that contains a list of converters. */
7696 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02007697 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007698 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007699 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007700
7701 /* Create the "sc" field that contains a list of stringsafe converters. */
7702 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01007703 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007704 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007705 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007706
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007707 /* Create the "req" field that contains the request channel object. */
7708 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007709 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007710 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007711 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007712
7713 /* Create the "res" field that contains the response channel object. */
7714 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007715 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007716 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007717 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007718
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007719 /* Creates the HTTP object is the current proxy allows http. */
7720 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01007721 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02007722 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007723 return 0;
7724 }
7725 else
7726 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007727 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007728
Christopher Faulet78c35472020-02-26 17:14:08 +01007729 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX) {
7730 /* HTTPMessage object are created when a lua TXN is created from
7731 * a filter context only
7732 */
7733
7734 /* Creates the HTTP-Request object is the current proxy allows http. */
7735 lua_pushstring(L, "http_req");
7736 if (p->mode == PR_MODE_HTTP) {
7737 if (!hlua_http_msg_new(L, &s->txn->req))
7738 return 0;
7739 }
7740 else
7741 lua_pushnil(L);
7742 lua_rawset(L, -3);
7743
7744 /* Creates the HTTP-Response object is the current proxy allows http. */
7745 lua_pushstring(L, "http_res");
7746 if (p->mode == PR_MODE_HTTP) {
7747 if (!hlua_http_msg_new(L, &s->txn->rsp))
7748 return 0;
7749 }
7750 else
7751 lua_pushnil(L);
7752 lua_rawset(L, -3);
7753 }
7754
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007755 /* Pop a class sesison metatable and affect it to the userdata. */
7756 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
7757 lua_setmetatable(L, -2);
7758
7759 return 1;
7760}
7761
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01007762__LJMP static int hlua_txn_deflog(lua_State *L)
7763{
7764 const char *msg;
7765 struct hlua_txn *htxn;
7766
7767 MAY_LJMP(check_args(L, 2, "deflog"));
7768 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7769 msg = MAY_LJMP(luaL_checkstring(L, 2));
7770
7771 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
7772 return 0;
7773}
7774
7775__LJMP static int hlua_txn_log(lua_State *L)
7776{
7777 int level;
7778 const char *msg;
7779 struct hlua_txn *htxn;
7780
7781 MAY_LJMP(check_args(L, 3, "log"));
7782 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7783 level = MAY_LJMP(luaL_checkinteger(L, 2));
7784 msg = MAY_LJMP(luaL_checkstring(L, 3));
7785
7786 if (level < 0 || level >= NB_LOG_LEVELS)
7787 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
7788
7789 hlua_sendlog(htxn->s->be, level, msg);
7790 return 0;
7791}
7792
7793__LJMP static int hlua_txn_log_debug(lua_State *L)
7794{
7795 const char *msg;
7796 struct hlua_txn *htxn;
7797
7798 MAY_LJMP(check_args(L, 2, "Debug"));
7799 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7800 msg = MAY_LJMP(luaL_checkstring(L, 2));
7801 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
7802 return 0;
7803}
7804
7805__LJMP static int hlua_txn_log_info(lua_State *L)
7806{
7807 const char *msg;
7808 struct hlua_txn *htxn;
7809
7810 MAY_LJMP(check_args(L, 2, "Info"));
7811 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7812 msg = MAY_LJMP(luaL_checkstring(L, 2));
7813 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
7814 return 0;
7815}
7816
7817__LJMP static int hlua_txn_log_warning(lua_State *L)
7818{
7819 const char *msg;
7820 struct hlua_txn *htxn;
7821
7822 MAY_LJMP(check_args(L, 2, "Warning"));
7823 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7824 msg = MAY_LJMP(luaL_checkstring(L, 2));
7825 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
7826 return 0;
7827}
7828
7829__LJMP static int hlua_txn_log_alert(lua_State *L)
7830{
7831 const char *msg;
7832 struct hlua_txn *htxn;
7833
7834 MAY_LJMP(check_args(L, 2, "Alert"));
7835 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7836 msg = MAY_LJMP(luaL_checkstring(L, 2));
7837 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
7838 return 0;
7839}
7840
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007841__LJMP static int hlua_txn_set_loglevel(lua_State *L)
7842{
7843 struct hlua_txn *htxn;
7844 int ll;
7845
7846 MAY_LJMP(check_args(L, 2, "set_loglevel"));
7847 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7848 ll = MAY_LJMP(luaL_checkinteger(L, 2));
7849
7850 if (ll < 0 || ll > 7)
7851 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
7852
7853 htxn->s->logs.level = ll;
7854 return 0;
7855}
7856
7857__LJMP static int hlua_txn_set_tos(lua_State *L)
7858{
7859 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007860 int tos;
7861
7862 MAY_LJMP(check_args(L, 2, "set_tos"));
7863 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7864 tos = MAY_LJMP(luaL_checkinteger(L, 2));
7865
Willy Tarreau1a18b542018-12-11 16:37:42 +01007866 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007867 return 0;
7868}
7869
7870__LJMP static int hlua_txn_set_mark(lua_State *L)
7871{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007872 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007873 int mark;
7874
7875 MAY_LJMP(check_args(L, 2, "set_mark"));
7876 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7877 mark = MAY_LJMP(luaL_checkinteger(L, 2));
7878
Lukas Tribus579e3e32019-08-11 18:03:45 +02007879 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007880 return 0;
7881}
7882
Patrick Hemmer268a7072018-05-11 12:52:31 -04007883__LJMP static int hlua_txn_set_priority_class(lua_State *L)
7884{
7885 struct hlua_txn *htxn;
7886
7887 MAY_LJMP(check_args(L, 2, "set_priority_class"));
7888 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7889 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
7890 return 0;
7891}
7892
7893__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
7894{
7895 struct hlua_txn *htxn;
7896
7897 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
7898 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7899 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
7900 return 0;
7901}
7902
Christopher Faulet700d9e82020-01-31 12:21:52 +01007903/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007904 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01007905 * message and terminate the transaction. It returns 1 on success and 0 on
7906 * error. The Reply must be on top of the stack.
7907 */
7908__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
7909{
7910 struct htx *htx;
7911 struct htx_sl *sl;
7912 struct h1m h1m;
7913 const char *status, *reason, *body;
7914 size_t status_len, reason_len, body_len;
7915 int ret, code, flags;
7916
7917 code = 200;
7918 status = "200";
7919 status_len = 3;
7920 ret = lua_getfield(L, -1, "status");
7921 if (ret == LUA_TNUMBER) {
7922 code = lua_tointeger(L, -1);
7923 status = lua_tolstring(L, -1, &status_len);
7924 }
7925 lua_pop(L, 1);
7926
7927 reason = http_get_reason(code);
7928 reason_len = strlen(reason);
7929 ret = lua_getfield(L, -1, "reason");
7930 if (ret == LUA_TSTRING)
7931 reason = lua_tolstring(L, -1, &reason_len);
7932 lua_pop(L, 1);
7933
7934 body = NULL;
7935 body_len = 0;
7936 ret = lua_getfield(L, -1, "body");
7937 if (ret == LUA_TSTRING)
7938 body = lua_tolstring(L, -1, &body_len);
7939 lua_pop(L, 1);
7940
7941 /* Prepare the response before inserting the headers */
7942 h1m_init_res(&h1m);
7943 htx = htx_from_buf(&s->res.buf);
7944 channel_htx_truncate(&s->res, htx);
7945 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
7946 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
7947 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
7948 ist2(status, status_len), ist2(reason, reason_len));
7949 }
7950 else {
7951 flags = HTX_SL_F_IS_RESP;
7952 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
7953 ist2(status, status_len), ist2(reason, reason_len));
7954 }
7955 if (!sl)
7956 goto fail;
7957 sl->info.res.status = code;
7958
7959 /* Push in the stack the "headers" entry. */
7960 ret = lua_getfield(L, -1, "headers");
7961 if (ret != LUA_TTABLE)
7962 goto skip_headers;
7963
7964 lua_pushnil(L);
7965 while (lua_next(L, -2) != 0) {
7966 struct ist name, value;
7967 const char *n, *v;
7968 size_t nlen, vlen;
7969
7970 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
7971 /* Skip element if the key is not a string or if the value is not a table */
7972 goto next_hdr;
7973 }
7974
7975 n = lua_tolstring(L, -2, &nlen);
7976 name = ist2(n, nlen);
7977 if (isteqi(name, ist("content-length"))) {
7978 /* Always skip content-length header. It will be added
7979 * later with the correct len
7980 */
7981 goto next_hdr;
7982 }
7983
7984 /* Loop on header's values */
7985 lua_pushnil(L);
7986 while (lua_next(L, -2)) {
7987 if (!lua_isstring(L, -1)) {
7988 /* Skip the value if it is not a string */
7989 goto next_value;
7990 }
7991
7992 v = lua_tolstring(L, -1, &vlen);
7993 value = ist2(v, vlen);
7994
7995 if (isteqi(name, ist("transfer-encoding")))
7996 h1_parse_xfer_enc_header(&h1m, value);
7997 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
7998 goto fail;
7999
8000 next_value:
8001 lua_pop(L, 1);
8002 }
8003
8004 next_hdr:
8005 lua_pop(L, 1);
8006 }
8007 skip_headers:
8008 lua_pop(L, 1);
8009
8010 /* Update h1m flags: CLEN is set if CHNK is not present */
8011 if (!(h1m.flags & H1_MF_CHNK)) {
8012 const char *clen = ultoa(body_len);
8013
8014 h1m.flags |= H1_MF_CLEN;
8015 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
8016 goto fail;
8017 }
8018 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
8019 h1m.flags |= H1_MF_XFER_LEN;
8020
8021 /* Update HTX start-line flags */
8022 if (h1m.flags & H1_MF_XFER_ENC)
8023 flags |= HTX_SL_F_XFER_ENC;
8024 if (h1m.flags & H1_MF_XFER_LEN) {
8025 flags |= HTX_SL_F_XFER_LEN;
8026 if (h1m.flags & H1_MF_CHNK)
8027 flags |= HTX_SL_F_CHNK;
8028 else if (h1m.flags & H1_MF_CLEN)
8029 flags |= HTX_SL_F_CLEN;
8030 if (h1m.body_len == 0)
8031 flags |= HTX_SL_F_BODYLESS;
8032 }
8033 sl->flags |= flags;
8034
8035
8036 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008037 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01008038 goto fail;
8039
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008040 htx->flags |= HTX_FL_EOM;
8041
Christopher Faulet700d9e82020-01-31 12:21:52 +01008042 /* Now, forward the response and terminate the transaction */
8043 s->txn->status = code;
8044 htx_to_buf(htx, &s->res.buf);
8045 if (!http_forward_proxy_resp(s, 1))
8046 goto fail;
8047
8048 return 1;
8049
8050 fail:
8051 channel_htx_truncate(&s->res, htx);
8052 return 0;
8053}
8054
8055/* Terminate a transaction if called from a lua action. For TCP streams,
8056 * processing is just aborted. Nothing is returned to the client and all
8057 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
8058 * is forwarded to the client before terminating the transaction. On success,
8059 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
8060 * with ACT_RET_ERR code. If this function is not called from a lua action, it
8061 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008062 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008063__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008064{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008065 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01008066 struct stream *s;
8067 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008068
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008069 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008070
Christopher Faulet700d9e82020-01-31 12:21:52 +01008071 /* If the flags NOTERM is set, we cannot terminate the session, so we
8072 * just end the execution of the current lua code. */
8073 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008074 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008075
Christopher Faulet700d9e82020-01-31 12:21:52 +01008076 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008077 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008078 struct channel *req = &s->req;
8079 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01008080
Christopher Faulet700d9e82020-01-31 12:21:52 +01008081 channel_auto_read(req);
8082 channel_abort(req);
8083 channel_auto_close(req);
8084 channel_erase(req);
8085
Christopher Faulet5aaacfb2023-02-15 08:13:33 +01008086 sc_ep_set_wex(s->scb, s->scf->ioto);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008087 channel_auto_read(res);
8088 channel_auto_close(res);
8089 channel_shutr_now(res);
8090
8091 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
8092 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008093 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02008094
Christopher Faulet700d9e82020-01-31 12:21:52 +01008095 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
8096 /* No reply or invalid reply */
8097 s->txn->status = 0;
8098 http_reply_and_close(s, 0, NULL);
8099 }
8100 else {
8101 /* Remove extra args to have the reply on top of the stack */
8102 if (lua_gettop(L) > 2)
8103 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008104
Christopher Faulet700d9e82020-01-31 12:21:52 +01008105 if (!hlua_txn_forward_reply(L, s)) {
8106 if (!(s->flags & SF_ERR_MASK))
8107 s->flags |= SF_ERR_PRXCOND;
8108 lua_pushinteger(L, ACT_RET_ERR);
8109 WILL_LJMP(hlua_done(L));
8110 return 0; /* Never reached */
8111 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02008112 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008113
Christopher Faulet700d9e82020-01-31 12:21:52 +01008114 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
8115 if (htxn->dir == SMP_OPT_DIR_REQ) {
8116 /* let's log the request time */
8117 s->logs.tv_request = now;
8118 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02008119 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008120 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008121
Christopher Faulet700d9e82020-01-31 12:21:52 +01008122 done:
8123 if (!(s->flags & SF_ERR_MASK))
8124 s->flags |= SF_ERR_LOCAL;
8125 if (!(s->flags & SF_FINST_MASK))
8126 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008127
Christopher Faulete48d1dc2021-08-13 14:11:17 +02008128 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX)
8129 lua_pushinteger(L, -1);
8130 else
8131 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008132 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008133 return 0;
8134}
8135
Christopher Faulet700d9e82020-01-31 12:21:52 +01008136/*
8137 *
8138 *
8139 * Class REPLY
8140 *
8141 *
8142 */
8143
8144/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
8145 * free slots, the function fails and returns 0;
8146 */
8147static int hlua_txn_reply_new(lua_State *L)
8148{
8149 struct hlua_txn *htxn;
8150 const char *reason, *body = NULL;
8151 int ret, status;
8152
8153 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008154 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008155 hlua_pusherror(L, "txn object is not an HTTP transaction.");
8156 WILL_LJMP(lua_error(L));
8157 }
8158
8159 /* Default value */
8160 status = 200;
8161 reason = http_get_reason(status);
8162
8163 if (lua_istable(L, 2)) {
8164 /* load status and reason from the table argument at index 2 */
8165 ret = lua_getfield(L, 2, "status");
8166 if (ret == LUA_TNIL)
8167 goto reason;
8168 else if (ret != LUA_TNUMBER) {
8169 /* invalid status: ignore the reason */
8170 goto body;
8171 }
8172 status = lua_tointeger(L, -1);
8173
8174 reason:
8175 lua_pop(L, 1); /* restore the stack: remove status */
8176 ret = lua_getfield(L, 2, "reason");
8177 if (ret == LUA_TSTRING)
8178 reason = lua_tostring(L, -1);
8179
8180 body:
8181 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
8182 ret = lua_getfield(L, 2, "body");
8183 if (ret == LUA_TSTRING)
8184 body = lua_tostring(L, -1);
8185 lua_pop(L, 1); /* restore the stack: remove body */
8186 }
8187
8188 /* Create the Reply table */
8189 lua_newtable(L);
8190
8191 /* Add status element */
8192 lua_pushstring(L, "status");
8193 lua_pushinteger(L, status);
8194 lua_settable(L, -3);
8195
8196 /* Add reason element */
8197 reason = http_get_reason(status);
8198 lua_pushstring(L, "reason");
8199 lua_pushstring(L, reason);
8200 lua_settable(L, -3);
8201
8202 /* Add body element, nil if undefined */
8203 lua_pushstring(L, "body");
8204 if (body)
8205 lua_pushstring(L, body);
8206 else
8207 lua_pushnil(L);
8208 lua_settable(L, -3);
8209
8210 /* Add headers element */
8211 lua_pushstring(L, "headers");
8212 lua_newtable(L);
8213
8214 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8215 if (lua_istable(L, 2)) {
8216 /* load headers from the table argument at index 2. If it is a table, copy it. */
8217 ret = lua_getfield(L, 2, "headers");
8218 if (ret == LUA_TTABLE) {
8219 /* stack: [ ... <headers:table>, <table> ] */
8220 lua_pushnil(L);
8221 while (lua_next(L, -2) != 0) {
8222 /* stack: [ ... <headers:table>, <table>, k, v] */
8223 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
8224 /* invalid value type, skip it */
8225 lua_pop(L, 1);
8226 continue;
8227 }
8228
8229
8230 /* Duplicate the key and swap it with the value. */
8231 lua_pushvalue(L, -2);
8232 lua_insert(L, -2);
8233 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
8234
8235 lua_newtable(L);
8236 lua_insert(L, -2);
8237 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
8238
8239 if (lua_isstring(L, -1)) {
8240 /* push the value in the inner table */
8241 lua_rawseti(L, -2, 1);
8242 }
8243 else { /* table */
8244 lua_pushnil(L);
8245 while (lua_next(L, -2) != 0) {
8246 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
8247 if (!lua_isstring(L, -1)) {
8248 /* invalid value type, skip it*/
8249 lua_pop(L, 1);
8250 continue;
8251 }
8252 /* push the value in the inner table */
8253 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
8254 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
8255 }
8256 lua_pop(L, 1);
8257 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
8258 }
8259
8260 /* push (k,v) on the stack in the headers table:
8261 * stack: [ ... <headers:table>, <table>, k, k, v ]
8262 */
8263 lua_settable(L, -5);
8264 /* stack: [ ... <headers:table>, <table>, k ] */
8265 }
8266 }
8267 lua_pop(L, 1);
8268 }
8269 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8270 lua_settable(L, -3);
8271 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
8272
8273 /* Pop a class sesison metatable and affect it to the userdata. */
8274 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
8275 lua_setmetatable(L, -2);
8276 return 1;
8277}
8278
8279/* Set the reply status code, and optionally the reason. If no reason is
8280 * provided, the default one corresponding to the status code is used.
8281 */
8282__LJMP static int hlua_txn_reply_set_status(lua_State *L)
8283{
8284 int status = MAY_LJMP(luaL_checkinteger(L, 2));
8285 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
8286
8287 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008288 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008289
8290 if (status < 100 || status > 599) {
8291 lua_pushboolean(L, 0);
8292 return 1;
8293 }
8294 if (!reason)
8295 reason = http_get_reason(status);
8296
8297 lua_pushinteger(L, status);
8298 lua_setfield(L, 1, "status");
8299
8300 lua_pushstring(L, reason);
8301 lua_setfield(L, 1, "reason");
8302
8303 lua_pushboolean(L, 1);
8304 return 1;
8305}
8306
8307/* Add a header into the reply object. Each header name is associated to an
8308 * array of values in the "headers" table. If the header name is not found, a
8309 * new entry is created.
8310 */
8311__LJMP static int hlua_txn_reply_add_header(lua_State *L)
8312{
8313 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8314 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
8315 int ret;
8316
8317 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008318 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008319
8320 /* Push in the stack the "headers" entry. */
8321 ret = lua_getfield(L, 1, "headers");
8322 if (ret != LUA_TTABLE) {
8323 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
8324 WILL_LJMP(lua_error(L));
8325 }
8326
8327 /* check if the header is already registered. If not, register it. */
8328 ret = lua_getfield(L, -1, name);
8329 if (ret == LUA_TNIL) {
8330 /* Entry not found. */
8331 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
8332
8333 /* Insert the new header name in the array in the top of the stack.
8334 * It left the new array in the top of the stack.
8335 */
8336 lua_newtable(L);
8337 lua_pushstring(L, name);
8338 lua_pushvalue(L, -2);
8339 lua_settable(L, -4);
8340 }
8341 else if (ret != LUA_TTABLE) {
8342 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
8343 WILL_LJMP(lua_error(L));
8344 }
8345
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008346 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01008347 * the header value as new entry.
8348 */
8349 lua_pushstring(L, value);
8350 ret = lua_rawlen(L, -2);
8351 lua_rawseti(L, -2, ret + 1);
8352
8353 lua_pushboolean(L, 1);
8354 return 1;
8355}
8356
8357/* Remove all occurrences of a given header name. */
8358__LJMP static int hlua_txn_reply_del_header(lua_State *L)
8359{
8360 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8361 int ret;
8362
8363 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008364 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008365
8366 /* Push in the stack the "headers" entry. */
8367 ret = lua_getfield(L, 1, "headers");
8368 if (ret != LUA_TTABLE) {
8369 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
8370 WILL_LJMP(lua_error(L));
8371 }
8372
8373 lua_pushstring(L, name);
8374 lua_pushnil(L);
8375 lua_settable(L, -3);
8376
8377 lua_pushboolean(L, 1);
8378 return 1;
8379}
8380
8381/* Set the reply's body. Overwrite any existing entry. */
8382__LJMP static int hlua_txn_reply_set_body(lua_State *L)
8383{
8384 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
8385
8386 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008387 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008388
8389 lua_pushstring(L, payload);
8390 lua_setfield(L, 1, "body");
8391
8392 lua_pushboolean(L, 1);
8393 return 1;
8394}
8395
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008396__LJMP static int hlua_log(lua_State *L)
8397{
8398 int level;
8399 const char *msg;
8400
8401 MAY_LJMP(check_args(L, 2, "log"));
8402 level = MAY_LJMP(luaL_checkinteger(L, 1));
8403 msg = MAY_LJMP(luaL_checkstring(L, 2));
8404
8405 if (level < 0 || level >= NB_LOG_LEVELS)
8406 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
8407
8408 hlua_sendlog(NULL, level, msg);
8409 return 0;
8410}
8411
8412__LJMP static int hlua_log_debug(lua_State *L)
8413{
8414 const char *msg;
8415
8416 MAY_LJMP(check_args(L, 1, "debug"));
8417 msg = MAY_LJMP(luaL_checkstring(L, 1));
8418 hlua_sendlog(NULL, LOG_DEBUG, msg);
8419 return 0;
8420}
8421
8422__LJMP static int hlua_log_info(lua_State *L)
8423{
8424 const char *msg;
8425
8426 MAY_LJMP(check_args(L, 1, "info"));
8427 msg = MAY_LJMP(luaL_checkstring(L, 1));
8428 hlua_sendlog(NULL, LOG_INFO, msg);
8429 return 0;
8430}
8431
8432__LJMP static int hlua_log_warning(lua_State *L)
8433{
8434 const char *msg;
8435
8436 MAY_LJMP(check_args(L, 1, "warning"));
8437 msg = MAY_LJMP(luaL_checkstring(L, 1));
8438 hlua_sendlog(NULL, LOG_WARNING, msg);
8439 return 0;
8440}
8441
8442__LJMP static int hlua_log_alert(lua_State *L)
8443{
8444 const char *msg;
8445
8446 MAY_LJMP(check_args(L, 1, "alert"));
8447 msg = MAY_LJMP(luaL_checkstring(L, 1));
8448 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008449 return 0;
8450}
8451
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008452__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008453{
8454 int wakeup_ms = lua_tointeger(L, -1);
Willy Tarreau12c02702021-09-30 16:12:31 +02008455 if (!tick_is_expired(wakeup_ms, now_ms))
Willy Tarreau9635e032018-10-16 17:52:55 +02008456 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008457 return 0;
8458}
8459
8460__LJMP static int hlua_sleep(lua_State *L)
8461{
8462 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008463 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008464
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008465 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008466
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008467 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008468 wakeup_ms = tick_add(now_ms, delay);
8469 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008470
Willy Tarreau9635e032018-10-16 17:52:55 +02008471 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008472 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008473}
8474
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008475__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008476{
8477 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008478 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008479
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008480 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008481
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008482 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008483 wakeup_ms = tick_add(now_ms, delay);
8484 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008485
Willy Tarreau9635e032018-10-16 17:52:55 +02008486 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008487 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008488}
8489
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008490/* This functionis an LUA binding. it permits to give back
8491 * the hand at the HAProxy scheduler. It is used when the
8492 * LUA processing consumes a lot of time.
8493 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008494__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008495{
8496 return 0;
8497}
8498
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008499__LJMP static int hlua_yield(lua_State *L)
8500{
Willy Tarreau9635e032018-10-16 17:52:55 +02008501 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008502 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008503}
8504
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008505/* This function change the nice of the currently executed
8506 * task. It is used set low or high priority at the current
8507 * task.
8508 */
Willy Tarreau59551662015-03-10 14:23:13 +01008509__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008510{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008511 struct hlua *hlua;
8512 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008513
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008514 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008515 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008516
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008517 /* Get hlua struct, or NULL if we execute from main lua state */
8518 hlua = hlua_gethlua(L);
8519
8520 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008521 if (!hlua || !hlua->task)
8522 return 0;
8523
8524 if (nice < -1024)
8525 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008526 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008527 nice = 1024;
8528
8529 hlua->task->nice = nice;
8530 return 0;
8531}
8532
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008533/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008534 * HAProxy task subsystem when the task is awaked. The LUA runtime can
8535 * return an E_AGAIN signal, the emmiter of this signal must set a
8536 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008537 *
8538 * Task wrapper are longjmp safe because the only one Lua code
8539 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008540 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01008541struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008542{
Olivier Houchard9f6af332018-05-25 14:04:04 +02008543 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008544 enum hlua_exec status;
8545
Willy Tarreau6ef52f42022-06-15 14:19:48 +02008546 if (task->tid < 0)
8547 task->tid = tid;
8548
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008549 /* If it is the first call to the task, we must initialize the
8550 * execution timeouts.
8551 */
8552 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02008553 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008554
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008555 /* Execute the Lua code. */
8556 status = hlua_ctx_resume(hlua, 1);
8557
8558 switch (status) {
8559 /* finished or yield */
8560 case HLUA_E_OK:
8561 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008562 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02008563 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008564 break;
8565
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01008566 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01008567 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02008568 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008569 break;
8570
8571 /* finished with error. */
8572 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008573 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008574 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008575 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02008576 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008577 break;
8578
8579 case HLUA_E_ERR:
8580 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008581 SEND_ERR(NULL, "Lua task: unknown error.\n");
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008582 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008583 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02008584 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008585 break;
8586 }
Emeric Brun253e53e2017-10-17 18:58:40 +02008587 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008588}
8589
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008590/* This function is an LUA binding that register LUA function to be
8591 * executed after the HAProxy configuration parsing and before the
8592 * HAProxy scheduler starts. This function expect only one LUA
8593 * argument that is a function. This function returns nothing, but
8594 * throws if an error is encountered.
8595 */
8596__LJMP static int hlua_register_init(lua_State *L)
8597{
8598 struct hlua_init_function *init;
8599 int ref;
8600
8601 MAY_LJMP(check_args(L, 1, "register_init"));
8602
8603 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8604
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008605 init = calloc(1, sizeof(*init));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008606 if (!init)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008607 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008608
8609 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02008610 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008611 return 0;
8612}
8613
Ilya Shipitsin6f86eaa2022-11-30 16:22:42 +05008614/* This function is an LUA binding. It permits to register a task
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008615 * executed in parallel of the main HAroxy activity. The task is
8616 * created and it is set in the HAProxy scheduler. It can be called
8617 * from the "init" section, "post init" or during the runtime.
8618 *
8619 * Lua prototype:
8620 *
8621 * <none> core.register_task(<function>)
8622 */
8623static int hlua_register_task(lua_State *L)
8624{
Christopher Faulet5294ec02021-04-12 12:24:47 +02008625 struct hlua *hlua = NULL;
8626 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008627 int ref;
Thierry Fournier021d9862020-11-28 23:42:03 +01008628 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008629
8630 MAY_LJMP(check_args(L, 1, "register_task"));
8631
8632 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8633
Thierry Fournier75fc0292020-11-28 13:18:56 +01008634 /* Get the reference state. If the reference is NULL, L is the master
8635 * state, otherwise hlua->T is.
8636 */
8637 hlua = hlua_gethlua(L);
8638 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01008639 /* we are in runtime processing */
8640 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008641 else
Thierry Fournier021d9862020-11-28 23:42:03 +01008642 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01008643 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008644
Willy Tarreaubafbe012017-11-24 17:34:44 +01008645 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008646 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008647 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008648 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008649
Thierry Fournier59f11be2020-11-29 00:37:41 +01008650 /* We are in the common lua state, execute the task anywhere,
8651 * otherwise, inherit the current thread identifier
8652 */
8653 if (state_id == 0)
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008654 task = task_new_anywhere();
Thierry Fournier59f11be2020-11-29 00:37:41 +01008655 else
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008656 task = task_new_here();
Willy Tarreaue09101e2018-10-16 17:37:12 +02008657 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008658 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02008659
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008660 task->context = hlua;
8661 task->process = hlua_process_task;
8662
Thierry Fournier021d9862020-11-28 23:42:03 +01008663 if (!hlua_ctx_init(hlua, state_id, task, 1))
Christopher Faulet5294ec02021-04-12 12:24:47 +02008664 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008665
8666 /* Restore the function in the stack. */
8667 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref);
8668 hlua->nargs = 0;
8669
8670 /* Schedule task. */
Willy Tarreaue3957f82021-09-30 16:17:37 +02008671 task_wakeup(task, TASK_WOKEN_INIT);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008672
8673 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02008674
8675 alloc_error:
8676 task_destroy(task);
8677 hlua_ctx_destroy(hlua);
8678 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8679 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008680}
8681
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008682/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
8683 * doesn't allow "yield" functions because the HAProxy engine cannot
8684 * resume converters.
8685 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008686static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008687{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008688 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008689 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008690 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008691
Willy Tarreaube508f12016-03-10 11:47:01 +01008692 if (!stream)
8693 return 0;
8694
Willy Tarreau87b09662015-04-03 00:22:06 +02008695 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008696 * Lua context can be not initialized. This behavior
8697 * permits to save performances because a systematic
8698 * Lua initialization cause 5% performances loss.
8699 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008700 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008701 struct hlua *hlua;
8702
8703 hlua = pool_alloc(pool_head_hlua);
8704 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008705 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
8706 return 0;
8707 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008708 HLUA_INIT(hlua);
8709 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01008710 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008711 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
8712 return 0;
8713 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008714 }
8715
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008716 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008717 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008718
8719 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008720 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008721 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
8722 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01008723 else
8724 error = "critical error";
8725 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008726 return 0;
8727 }
8728
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008729 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008730 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008731 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008732 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008733 return 0;
8734 }
8735
8736 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01008737 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008738
8739 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008740 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008741 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008742 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008743 return 0;
8744 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008745 hlua_smp2lua(stream->hlua->T, smp);
8746 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008747
8748 /* push keywords in the stack. */
8749 if (arg_p) {
8750 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008751 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008752 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008753 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008754 return 0;
8755 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008756 hlua_arg2lua(stream->hlua->T, arg_p);
8757 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008758 }
8759 }
8760
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008761 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008762 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008763
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008764 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008765 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008766 }
8767
8768 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008769 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008770 /* finished. */
8771 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02008772 /* If the stack is empty, the function fails. */
8773 if (lua_gettop(stream->hlua->T) <= 0)
8774 return 0;
8775
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008776 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008777 hlua_lua2smp(stream->hlua->T, -1, smp);
8778 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008779 return 1;
8780
8781 /* yield. */
8782 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008783 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008784 return 0;
8785
8786 /* finished with error. */
8787 case HLUA_E_ERRMSG:
8788 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008789 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008790 fcn->name, lua_tostring(stream->hlua->T, -1));
8791 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008792 return 0;
8793
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008794 case HLUA_E_ETMOUT:
8795 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
8796 return 0;
8797
8798 case HLUA_E_NOMEM:
8799 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
8800 return 0;
8801
8802 case HLUA_E_YIELD:
8803 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
8804 return 0;
8805
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008806 case HLUA_E_ERR:
8807 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008808 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01008809 __fallthrough;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008810
8811 default:
8812 return 0;
8813 }
8814}
8815
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008816/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
8817 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01008818 * resume sample-fetches. This function will be called by the sample
8819 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008820 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02008821static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
8822 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008823{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008824 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008825 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008826 const char *error;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02008827 unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008828
Willy Tarreaube508f12016-03-10 11:47:01 +01008829 if (!stream)
8830 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01008831
Willy Tarreau87b09662015-04-03 00:22:06 +02008832 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008833 * Lua context can be not initialized. This behavior
8834 * permits to save performances because a systematic
8835 * Lua initialization cause 5% performances loss.
8836 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008837 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008838 struct hlua *hlua;
8839
8840 hlua = pool_alloc(pool_head_hlua);
8841 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008842 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
8843 return 0;
8844 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008845 hlua->T = NULL;
8846 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01008847 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008848 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
8849 return 0;
8850 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008851 }
8852
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008853 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008854 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008855
8856 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008857 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008858 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
8859 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01008860 else
8861 error = "critical error";
8862 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008863 return 0;
8864 }
8865
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008866 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008867 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008868 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008869 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008870 return 0;
8871 }
8872
8873 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01008874 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008875
8876 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02008877 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008878 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008879 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008880 return 0;
8881 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008882 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008883
8884 /* push keywords in the stack. */
8885 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
8886 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008887 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008888 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008889 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008890 return 0;
8891 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008892 hlua_arg2lua(stream->hlua->T, arg_p);
8893 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008894 }
8895
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008896 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008897 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008898
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008899 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008900 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008901 }
8902
8903 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008904 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008905 /* finished. */
8906 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02008907 /* If the stack is empty, the function fails. */
8908 if (lua_gettop(stream->hlua->T) <= 0)
8909 return 0;
8910
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008911 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008912 hlua_lua2smp(stream->hlua->T, -1, smp);
8913 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008914
8915 /* Set the end of execution flag. */
8916 smp->flags &= ~SMP_F_MAY_CHANGE;
8917 return 1;
8918
8919 /* yield. */
8920 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008921 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008922 return 0;
8923
8924 /* finished with error. */
8925 case HLUA_E_ERRMSG:
8926 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008927 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008928 fcn->name, lua_tostring(stream->hlua->T, -1));
8929 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008930 return 0;
8931
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008932 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008933 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
8934 return 0;
8935
8936 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008937 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
8938 return 0;
8939
8940 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008941 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
8942 return 0;
8943
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008944 case HLUA_E_ERR:
8945 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008946 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01008947 __fallthrough;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008948
8949 default:
8950 return 0;
8951 }
8952}
8953
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008954/* This function is an LUA binding used for registering
8955 * "sample-conv" functions. It expects a converter name used
8956 * in the haproxy configuration file, and an LUA function.
8957 */
8958__LJMP static int hlua_register_converters(lua_State *L)
8959{
8960 struct sample_conv_kw_list *sck;
8961 const char *name;
8962 int ref;
8963 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02008964 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008965 struct sample_conv *sc;
8966 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008967
8968 MAY_LJMP(check_args(L, 2, "register_converters"));
8969
8970 /* First argument : converter name. */
8971 name = MAY_LJMP(luaL_checkstring(L, 1));
8972
8973 /* Second argument : lua function. */
8974 ref = MAY_LJMP(hlua_checkfunction(L, 2));
8975
Thierry Fournierf67442e2020-11-28 20:41:07 +01008976 /* Check if the converter is already registered */
8977 trash = get_trash_chunk();
8978 chunk_printf(trash, "lua.%s", name);
8979 sc = find_sample_conv(trash->area, trash->data);
8980 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008981 fcn = sc->private;
8982 if (fcn->function_ref[hlua_state_id] != -1) {
8983 ha_warning("Trying to register converter 'lua.%s' more than once. "
8984 "This will become a hard error in version 2.5.\n", name);
8985 }
8986 fcn->function_ref[hlua_state_id] = ref;
8987 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008988 }
8989
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008990 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008991 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008992 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +02008993 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008994 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008995 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +02008996 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008997
8998 /* Fill fcn. */
8999 fcn->name = strdup(name);
9000 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +02009001 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009002 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009003
9004 /* List head */
9005 sck->list.n = sck->list.p = NULL;
9006
9007 /* converter keyword. */
9008 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009009 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009010 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +02009011 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009012
9013 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
9014 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01009015 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 +01009016 sck->kw[0].val_args = NULL;
9017 sck->kw[0].in_type = SMP_T_STR;
9018 sck->kw[0].out_type = SMP_T_STR;
9019 sck->kw[0].private = fcn;
9020
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009021 /* Register this new converter */
9022 sample_register_convs(sck);
9023
9024 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +02009025
9026 alloc_error:
9027 release_hlua_function(fcn);
9028 ha_free(&sck);
9029 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9030 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009031}
9032
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009033/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009034 * "sample-fetch" functions. It expects a converter name used
9035 * in the haproxy configuration file, and an LUA function.
9036 */
9037__LJMP static int hlua_register_fetches(lua_State *L)
9038{
9039 const char *name;
9040 int ref;
9041 int len;
9042 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +02009043 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009044 struct sample_fetch *sf;
9045 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009046
9047 MAY_LJMP(check_args(L, 2, "register_fetches"));
9048
9049 /* First argument : sample-fetch name. */
9050 name = MAY_LJMP(luaL_checkstring(L, 1));
9051
9052 /* Second argument : lua function. */
9053 ref = MAY_LJMP(hlua_checkfunction(L, 2));
9054
Thierry Fournierf67442e2020-11-28 20:41:07 +01009055 /* Check if the sample-fetch is already registered */
9056 trash = get_trash_chunk();
9057 chunk_printf(trash, "lua.%s", name);
9058 sf = find_sample_fetch(trash->area, trash->data);
9059 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01009060 fcn = sf->private;
9061 if (fcn->function_ref[hlua_state_id] != -1) {
9062 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
9063 "This will become a hard error in version 2.5.\n", name);
9064 }
9065 fcn->function_ref[hlua_state_id] = ref;
9066 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009067 }
9068
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009069 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009070 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009071 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +02009072 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01009073 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009074 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +02009075 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009076
9077 /* Fill fcn. */
9078 fcn->name = strdup(name);
9079 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +02009080 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009081 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009082
9083 /* List head */
9084 sfk->list.n = sfk->list.p = NULL;
9085
9086 /* sample-fetch keyword. */
9087 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009088 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009089 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +02009090 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009091
9092 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
9093 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01009094 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 +01009095 sfk->kw[0].val_args = NULL;
9096 sfk->kw[0].out_type = SMP_T_STR;
9097 sfk->kw[0].use = SMP_USE_HTTP_ANY;
9098 sfk->kw[0].val = 0;
9099 sfk->kw[0].private = fcn;
9100
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009101 /* Register this new fetch. */
9102 sample_register_fetches(sfk);
9103
9104 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +02009105
9106 alloc_error:
9107 release_hlua_function(fcn);
9108 ha_free(&sfk);
9109 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9110 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009111}
9112
Christopher Faulet501465d2020-02-26 14:54:16 +01009113/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009114 */
Christopher Faulet501465d2020-02-26 14:54:16 +01009115__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009116{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009117 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009118 unsigned int delay;
9119 unsigned int wakeup_ms;
9120
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009121 /* Get hlua struct, or NULL if we execute from main lua state */
9122 hlua = hlua_gethlua(L);
9123 if (!hlua) {
9124 return 0;
9125 }
9126
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009127 MAY_LJMP(check_args(L, 1, "wake_time"));
9128
9129 delay = MAY_LJMP(luaL_checkinteger(L, 1));
9130 wakeup_ms = tick_add(now_ms, delay);
9131 hlua->wake_time = wakeup_ms;
9132 return 0;
9133}
9134
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009135/* This function is a wrapper to execute each LUA function declared as an action
9136 * wrapper during the initialisation period. This function may return any
9137 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
9138 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
9139 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009140 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009141static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02009142 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009143{
9144 char **arg;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02009145 unsigned int hflags = HLUA_TXN_ACT_CTX;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009146 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009147 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009148
9149 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01009150 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
9151 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
9152 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
9153 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009154 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009155 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009156 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009157 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009158
Willy Tarreau87b09662015-04-03 00:22:06 +02009159 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009160 * Lua context can be not initialized. This behavior
9161 * permits to save performances because a systematic
9162 * Lua initialization cause 5% performances loss.
9163 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009164 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009165 struct hlua *hlua;
9166
9167 hlua = pool_alloc(pool_head_hlua);
9168 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009169 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009170 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009171 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009172 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009173 HLUA_INIT(hlua);
9174 s->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01009175 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 +01009176 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009177 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009178 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009179 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009180 }
9181
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009182 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009183 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009184
9185 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009186 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009187 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
9188 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009189 else
9190 error = "critical error";
9191 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009192 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009193 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009194 }
9195
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009196 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009197 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009198 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009199 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009200 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009201 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009202 }
9203
9204 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01009205 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 +01009206
Willy Tarreau87b09662015-04-03 00:22:06 +02009207 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02009208 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009209 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009210 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009211 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009212 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009213 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009214 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009215
9216 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009217 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009218 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009219 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009220 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009221 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009222 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009223 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009224 lua_pushstring(s->hlua->T, *arg);
9225 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009226 }
9227
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009228 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009229 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009230
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009231 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009232 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009233 }
9234
9235 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01009236 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009237 /* finished. */
9238 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009239 /* Catch the return value */
9240 if (lua_gettop(s->hlua->T) > 0)
9241 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009242
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009243 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02009244 if (act_ret == ACT_RET_YIELD) {
9245 if (flags & ACT_OPT_FINAL)
9246 goto err_yield;
9247
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009248 if (dir == SMP_OPT_DIR_REQ)
9249 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
9250 s->hlua->wake_time);
9251 else
9252 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
9253 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009254 }
9255 goto end;
9256
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009257 /* yield. */
9258 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01009259 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009260 if (dir == SMP_OPT_DIR_REQ)
9261 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
9262 s->hlua->wake_time);
9263 else
9264 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
9265 s->hlua->wake_time);
9266
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009267 /* Some actions can be wake up when a "write" event
9268 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009269 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009270 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02009271 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009272 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009273 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009274 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009275 act_ret = ACT_RET_YIELD;
9276 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009277
9278 /* finished with error. */
9279 case HLUA_E_ERRMSG:
9280 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009281 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009282 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009283 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009284 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009285
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009286 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +01009287 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009288 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009289
9290 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +01009291 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009292 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009293
9294 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02009295 err_yield:
9296 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009297 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009298 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009299 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009300
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009301 case HLUA_E_ERR:
9302 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009303 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009304 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009305
9306 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009307 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009308 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009309
9310 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02009311 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009312 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009313 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009314}
9315
Willy Tarreau144f84a2021-03-02 16:09:26 +01009316struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009317{
Olivier Houchard9f6af332018-05-25 14:04:04 +02009318 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009319
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009320 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02009321 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02009322 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009323}
9324
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009325static int hlua_applet_tcp_init(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009326{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009327 struct hlua_tcp_ctx *tcp_ctx = applet_reserve_svcctx(ctx, sizeof(*tcp_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +02009328 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009329 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009330 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009331 struct task *task;
9332 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009333 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009334
Willy Tarreaubafbe012017-11-24 17:34:44 +01009335 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009336 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009337 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009338 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009339 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009340 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009341 HLUA_INIT(hlua);
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009342 tcp_ctx->hlua = hlua;
9343 tcp_ctx->flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009344
9345 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +02009346 task = task_new_here();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009347 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009348 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009349 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009350 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009351 }
9352 task->nice = 0;
9353 task->context = ctx;
9354 task->process = hlua_applet_wakeup;
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009355 tcp_ctx->task = task;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009356
9357 /* In the execution wrappers linked with a stream, the
9358 * Lua context can be not initialized. This behavior
9359 * permits to save performances because a systematic
9360 * Lua initialization cause 5% performances loss.
9361 */
Thierry Fournierc7492592020-11-28 23:57:24 +01009362 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009363 SEND_ERR(strm->be, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009364 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009365 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009366 }
9367
9368 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02009369 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009370
9371 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009372 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01009373 if (lua_type(hlua->T, -1) == LUA_TSTRING)
9374 error = lua_tostring(hlua->T, -1);
9375 else
9376 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009377 SEND_ERR(strm->be, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009378 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +02009379 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009380 }
9381
9382 /* Check stack available size. */
9383 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009384 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009385 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009386 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009387 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009388 }
9389
9390 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01009391 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009392
9393 /* Create and and push object stream in the stack. */
9394 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009395 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009396 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009397 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009398 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009399 }
9400 hlua->nargs = 1;
9401
9402 /* push keywords in the stack. */
9403 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
9404 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009405 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009406 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009407 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009408 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009409 }
9410 lua_pushstring(hlua->T, *arg);
9411 hlua->nargs++;
9412 }
9413
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009414 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009415
9416 /* Wakeup the applet ASAP. */
Willy Tarreau90e8b452022-05-25 18:21:43 +02009417 applet_need_more_data(ctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02009418 applet_have_more_data(ctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009419
Christopher Fauletc9929382022-05-12 11:52:27 +02009420 return 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009421}
9422
Willy Tarreau60409db2019-08-21 14:14:50 +02009423void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009424{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009425 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02009426 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009427 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009428 struct act_rule *rule = ctx->rule;
9429 struct proxy *px = strm->be;
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009430 struct hlua *hlua = tcp_ctx->hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009431
9432 /* The applet execution is already done. */
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009433 if (tcp_ctx->flags & APPLET_DONE) {
Olivier Houchard594c8c52018-08-28 14:41:31 +02009434 /* eat the whole request */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009435 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009436 return;
Olivier Houchard594c8c52018-08-28 14:41:31 +02009437 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009438
9439 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009440 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009441 return;
9442
9443 /* Execute the function. */
9444 switch (hlua_ctx_resume(hlua, 1)) {
9445 /* finished. */
9446 case HLUA_E_OK:
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009447 tcp_ctx->flags |= APPLET_DONE;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009448
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009449 /* eat the whole request */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009450 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
Willy Tarreau3e7be362022-05-27 10:35:27 +02009451 sc_shutr(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009452 return;
9453
9454 /* yield. */
9455 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01009456 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009457 task_schedule(tcp_ctx->task, hlua->wake_time);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009458 return;
9459
9460 /* finished with error. */
9461 case HLUA_E_ERRMSG:
9462 /* Display log. */
9463 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009464 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009465 lua_pop(hlua->T, 1);
9466 goto error;
9467
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009468 case HLUA_E_ETMOUT:
9469 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009470 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009471 goto error;
9472
9473 case HLUA_E_NOMEM:
9474 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009475 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009476 goto error;
9477
9478 case HLUA_E_YIELD: /* unexpected */
9479 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009480 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009481 goto error;
9482
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009483 case HLUA_E_ERR:
9484 /* Display log. */
9485 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009486 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009487 goto error;
9488
9489 default:
9490 goto error;
9491 }
9492
9493error:
9494
9495 /* For all other cases, just close the stream. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009496 sc_shutw(sc);
9497 sc_shutr(sc);
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009498 tcp_ctx->flags |= APPLET_DONE;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009499}
9500
9501static void hlua_applet_tcp_release(struct appctx *ctx)
9502{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009503 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
9504
9505 task_destroy(tcp_ctx->task);
9506 tcp_ctx->task = NULL;
9507 hlua_ctx_destroy(tcp_ctx->hlua);
9508 tcp_ctx->hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009509}
9510
Christopher Fauletc9929382022-05-12 11:52:27 +02009511/* The function returns 0 if the initialisation is complete or -1 if
9512 * an errors occurs. It also reserves the appctx for an hlua_http_ctx.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009513 */
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009514static int hlua_applet_http_init(struct appctx *ctx)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009515{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009516 struct hlua_http_ctx *http_ctx = applet_reserve_svcctx(ctx, sizeof(*http_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +02009517 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009518 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009519 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009520 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009521 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009522 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009523 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009524
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009525 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01009526 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009527 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009528 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009529 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009530 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009531 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009532 HLUA_INIT(hlua);
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009533 http_ctx->hlua = hlua;
9534 http_ctx->left_bytes = -1;
9535 http_ctx->flags = 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009536
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01009537 if (txn->req.flags & HTTP_MSGF_VER_11)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009538 http_ctx->flags |= APPLET_HTTP11;
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01009539
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009540 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +02009541 task = task_new_here();
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009542 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009543 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009544 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009545 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009546 }
9547 task->nice = 0;
9548 task->context = ctx;
9549 task->process = hlua_applet_wakeup;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009550 http_ctx->task = task;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009551
9552 /* In the execution wrappers linked with a stream, the
9553 * Lua context can be not initialized. This behavior
9554 * permits to save performances because a systematic
9555 * Lua initialization cause 5% performances loss.
9556 */
Thierry Fournierc7492592020-11-28 23:57:24 +01009557 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009558 SEND_ERR(strm->be, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009559 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009560 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009561 }
9562
9563 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02009564 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009565
9566 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009567 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01009568 if (lua_type(hlua->T, -1) == LUA_TSTRING)
9569 error = lua_tostring(hlua->T, -1);
9570 else
9571 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009572 SEND_ERR(strm->be, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009573 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +02009574 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009575 }
9576
9577 /* Check stack available size. */
9578 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009579 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009580 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009581 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009582 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009583 }
9584
9585 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01009586 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009587
9588 /* Create and and push object stream in the stack. */
9589 if (!hlua_applet_http_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009590 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009591 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009592 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009593 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009594 }
9595 hlua->nargs = 1;
9596
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009597 /* push keywords in the stack. */
9598 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
9599 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009600 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009601 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009602 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009603 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009604 }
9605 lua_pushstring(hlua->T, *arg);
9606 hlua->nargs++;
9607 }
9608
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009609 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009610
9611 /* Wakeup the applet when data is ready for read. */
Willy Tarreau90e8b452022-05-25 18:21:43 +02009612 applet_need_more_data(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009613
Christopher Fauletc9929382022-05-12 11:52:27 +02009614 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009615}
9616
Willy Tarreau60409db2019-08-21 14:14:50 +02009617void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009618{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009619 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02009620 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009621 struct stream *strm = __sc_strm(sc);
9622 struct channel *req = sc_oc(sc);
9623 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009624 struct act_rule *rule = ctx->rule;
9625 struct proxy *px = strm->be;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009626 struct hlua *hlua = http_ctx->hlua;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009627 struct htx *req_htx, *res_htx;
9628
9629 res_htx = htx_from_buf(&res->buf);
9630
9631 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009632 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009633 goto out;
9634
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009635 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009636 if (!b_size(&res->buf)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02009637 sc_need_room(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009638 goto out;
9639 }
9640 /* check that the output is not closed */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009641 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR))
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009642 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009643
9644 /* Set the currently running flag. */
9645 if (!HLUA_IS_RUNNING(hlua) &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009646 !(http_ctx->flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +02009647 if (!co_data(req)) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02009648 applet_need_more_data(ctx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009649 goto out;
9650 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009651 }
9652
9653 /* Executes The applet if it is not done. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009654 if (!(http_ctx->flags & APPLET_DONE)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009655
9656 /* Execute the function. */
9657 switch (hlua_ctx_resume(hlua, 1)) {
9658 /* finished. */
9659 case HLUA_E_OK:
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009660 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009661 break;
9662
9663 /* yield. */
9664 case HLUA_E_AGAIN:
9665 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009666 task_schedule(http_ctx->task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009667 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009668
9669 /* finished with error. */
9670 case HLUA_E_ERRMSG:
9671 /* Display log. */
9672 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009673 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009674 lua_pop(hlua->T, 1);
9675 goto error;
9676
9677 case HLUA_E_ETMOUT:
9678 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009679 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009680 goto error;
9681
9682 case HLUA_E_NOMEM:
9683 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009684 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009685 goto error;
9686
9687 case HLUA_E_YIELD: /* unexpected */
9688 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009689 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009690 goto error;
9691
9692 case HLUA_E_ERR:
9693 /* Display log. */
9694 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009695 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009696 goto error;
9697
9698 default:
9699 goto error;
9700 }
9701 }
9702
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009703 if (http_ctx->flags & APPLET_DONE) {
9704 if (http_ctx->flags & APPLET_RSP_SENT)
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009705 goto done;
9706
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009707 if (!(http_ctx->flags & APPLET_HDR_SENT))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009708 goto error;
9709
Christopher Fauletf89af9c2022-04-07 10:07:18 +02009710 /* no more data are expected. If the response buffer is empty
9711 * for a chunked message, be sure to add something (EOT block in
9712 * this case) to have something to send. It is important to be
9713 * sure the EOM flags will be handled by the endpoint.
9714 */
9715 if (htx_is_empty(res_htx) && (strm->txn->rsp.flags & (HTTP_MSGF_XFER_LEN|HTTP_MSGF_CNT_LEN)) == HTTP_MSGF_XFER_LEN) {
9716 if (!htx_add_endof(res_htx, HTX_BLK_EOT)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02009717 sc_need_room(sc);
Christopher Fauletf89af9c2022-04-07 10:07:18 +02009718 goto out;
9719 }
9720 channel_add_input(res, 1);
9721 }
9722
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01009723 res_htx->flags |= HTX_FL_EOM;
Christopher Fauletd8d27082022-03-07 15:50:54 +01009724 res->flags |= CF_EOI;
Willy Tarreaud869e132022-05-17 18:05:31 +02009725 se_fl_set(ctx->sedesc, SE_FL_EOI);
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009726 strm->txn->status = http_ctx->status;
9727 http_ctx->flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009728 }
9729
9730 done:
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009731 if (http_ctx->flags & APPLET_DONE) {
Christopher Fauletb08c5252023-02-20 07:55:19 +01009732 if (!(res->flags & CF_SHUTR))
Willy Tarreau3e7be362022-05-27 10:35:27 +02009733 sc_shutr(sc);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009734
9735 /* eat the whole request */
9736 if (co_data(req)) {
9737 req_htx = htx_from_buf(&req->buf);
9738 co_htx_skip(req, req_htx, co_data(req));
9739 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009740 }
9741 }
9742
9743 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009744 htx_to_buf(res_htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009745 return;
9746
9747 error:
9748
9749 /* If we are in HTTP mode, and we are not send any
9750 * data, return a 500 server error in best effort:
9751 * if there is no room available in the buffer,
9752 * just close the connection.
9753 */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009754 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02009755 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009756
9757 channel_erase(res);
9758 res->buf.data = b_data(err);
9759 memcpy(res->buf.area, b_head(err), b_data(err));
9760 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01009761 channel_add_input(res, res_htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009762 }
9763 if (!(strm->flags & SF_ERR_MASK))
9764 strm->flags |= SF_ERR_RESOURCE;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009765 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009766 goto done;
9767}
9768
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009769static void hlua_applet_http_release(struct appctx *ctx)
9770{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009771 struct hlua_http_ctx *http_ctx = ctx->svcctx;
9772
9773 task_destroy(http_ctx->task);
9774 http_ctx->task = NULL;
9775 hlua_ctx_destroy(http_ctx->hlua);
9776 http_ctx->hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009777}
9778
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009779/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009780 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009781 *
9782 * This function can fail with an abort() due to an Lua critical error.
9783 * We are in the configuration parsing process of HAProxy, this abort() is
9784 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009785 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009786static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
9787 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009788{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009789 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009790 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009791
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009792 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009793 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009794 if (!rule->arg.hlua_rule) {
9795 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009796 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009797 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009798
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009799 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02009800 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
9801 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009802 if (!rule->arg.hlua_rule->args) {
9803 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009804 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009805 }
9806
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009807 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01009808 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009809
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009810 /* Expect some arguments */
9811 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01009812 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009813 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +02009814 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009815 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01009816 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009817 if (!rule->arg.hlua_rule->args[i]) {
9818 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009819 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009820 }
9821 (*cur_arg)++;
9822 }
9823 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009824
Thierry FOURNIER42148732015-09-02 17:17:33 +02009825 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009826 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02009827 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +02009828
9829 error:
9830 if (rule->arg.hlua_rule) {
9831 if (rule->arg.hlua_rule->args) {
9832 for (i = 0; i < fcn->nargs; i++)
9833 ha_free(&rule->arg.hlua_rule->args[i]);
9834 ha_free(&rule->arg.hlua_rule->args);
9835 }
9836 ha_free(&rule->arg.hlua_rule);
9837 }
9838 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009839}
9840
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009841static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
9842 struct act_rule *rule, char **err)
9843{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009844 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009845
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009846 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009847 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009848 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009849 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009850 * the call of this analyzer.
9851 */
9852 if (rule->from != ACT_F_HTTP_REQ) {
9853 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
9854 return ACT_RET_PRS_ERR;
9855 }
9856
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009857 /* Memory for the rule. */
9858 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
9859 if (!rule->arg.hlua_rule) {
9860 memprintf(err, "out of memory error");
9861 return ACT_RET_PRS_ERR;
9862 }
9863
9864 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01009865 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009866
9867 /* TODO: later accept arguments. */
9868 rule->arg.hlua_rule->args = NULL;
9869
9870 /* Add applet pointer in the rule. */
9871 rule->applet.obj_type = OBJ_TYPE_APPLET;
9872 rule->applet.name = fcn->name;
9873 rule->applet.init = hlua_applet_http_init;
9874 rule->applet.fct = hlua_applet_http_fct;
9875 rule->applet.release = hlua_applet_http_release;
9876 rule->applet.timeout = hlua_timeout_applet;
9877
9878 return ACT_RET_PRS_OK;
9879}
9880
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009881/* This function is an LUA binding used for registering
9882 * "sample-conv" functions. It expects a converter name used
9883 * in the haproxy configuration file, and an LUA function.
9884 */
9885__LJMP static int hlua_register_action(lua_State *L)
9886{
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009887 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009888 const char *name;
9889 int ref;
9890 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009891 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009892 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009893 struct buffer *trash;
9894 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009895
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009896 /* Initialise the number of expected arguments at 0. */
9897 nargs = 0;
9898
9899 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
9900 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009901
9902 /* First argument : converter name. */
9903 name = MAY_LJMP(luaL_checkstring(L, 1));
9904
9905 /* Second argument : environment. */
9906 if (lua_type(L, 2) != LUA_TTABLE)
9907 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
9908
9909 /* Third argument : lua function. */
9910 ref = MAY_LJMP(hlua_checkfunction(L, 3));
9911
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009912 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009913 if (lua_gettop(L) >= 4)
9914 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
9915
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009916 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009917 lua_pushnil(L);
9918 while (lua_next(L, 2) != 0) {
9919 if (lua_type(L, -1) != LUA_TSTRING)
9920 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
9921
Thierry Fournierf67442e2020-11-28 20:41:07 +01009922 /* Check if action exists */
9923 trash = get_trash_chunk();
9924 chunk_printf(trash, "lua.%s", name);
9925 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
9926 akw = tcp_req_cont_action(trash->area);
9927 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
9928 akw = tcp_res_cont_action(trash->area);
9929 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
9930 akw = action_http_req_custom(trash->area);
9931 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
9932 akw = action_http_res_custom(trash->area);
9933 } else {
9934 akw = NULL;
9935 }
9936 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01009937 fcn = akw->private;
9938 if (fcn->function_ref[hlua_state_id] != -1) {
9939 ha_warning("Trying to register action 'lua.%s' more than once. "
9940 "This will become a hard error in version 2.5.\n", name);
9941 }
9942 fcn->function_ref[hlua_state_id] = ref;
9943
9944 /* pop the environment string. */
9945 lua_pop(L, 1);
9946 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009947 }
9948
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009949 /* Check required environment. Only accepted "http" or "tcp". */
9950 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009951 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009952 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009953 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01009954 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009955 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009956 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009957
9958 /* Fill fcn. */
9959 fcn->name = strdup(name);
9960 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009961 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009962 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009963
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07009964 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009965 fcn->nargs = nargs;
9966
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009967 /* List head */
9968 akl->list.n = akl->list.p = NULL;
9969
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009970 /* action keyword. */
9971 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009972 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009973 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009974 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009975
9976 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
9977
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02009978 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009979 akl->kw[0].private = fcn;
9980 akl->kw[0].parse = action_register_lua;
9981
9982 /* select the action registering point. */
9983 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
9984 tcp_req_cont_keywords_register(akl);
9985 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
9986 tcp_res_cont_keywords_register(akl);
9987 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
9988 http_req_keywords_register(akl);
9989 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
9990 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009991 else {
9992 release_hlua_function(fcn);
9993 if (akl)
9994 ha_free((char **)&(akl->kw[0].kw));
9995 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01009996 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009997 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
9998 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009999 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010000
10001 /* pop the environment string. */
10002 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010003
10004 /* reset for next loop */
10005 akl = NULL;
10006 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010007 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010008 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010009
10010 alloc_error:
10011 release_hlua_function(fcn);
10012 ha_free(&akl);
10013 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10014 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010015}
10016
10017static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
10018 struct act_rule *rule, char **err)
10019{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010020 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010021
Christopher Faulet280f85b2019-07-15 15:02:04 +020010022 if (px->mode == PR_MODE_HTTP) {
10023 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +010010024 return ACT_RET_PRS_ERR;
10025 }
10026
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010027 /* Memory for the rule. */
10028 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
10029 if (!rule->arg.hlua_rule) {
10030 memprintf(err, "out of memory error");
10031 return ACT_RET_PRS_ERR;
10032 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010033
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010034 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010035 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010036
10037 /* TODO: later accept arguments. */
10038 rule->arg.hlua_rule->args = NULL;
10039
10040 /* Add applet pointer in the rule. */
10041 rule->applet.obj_type = OBJ_TYPE_APPLET;
10042 rule->applet.name = fcn->name;
10043 rule->applet.init = hlua_applet_tcp_init;
10044 rule->applet.fct = hlua_applet_tcp_fct;
10045 rule->applet.release = hlua_applet_tcp_release;
10046 rule->applet.timeout = hlua_timeout_applet;
10047
10048 return 0;
10049}
10050
10051/* This function is an LUA binding used for registering
10052 * "sample-conv" functions. It expects a converter name used
10053 * in the haproxy configuration file, and an LUA function.
10054 */
10055__LJMP static int hlua_register_service(lua_State *L)
10056{
10057 struct action_kw_list *akl;
10058 const char *name;
10059 const char *env;
10060 int ref;
10061 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010062 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010063 struct buffer *trash;
10064 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010065
10066 MAY_LJMP(check_args(L, 3, "register_service"));
10067
10068 /* First argument : converter name. */
10069 name = MAY_LJMP(luaL_checkstring(L, 1));
10070
10071 /* Second argument : environment. */
10072 env = MAY_LJMP(luaL_checkstring(L, 2));
10073
10074 /* Third argument : lua function. */
10075 ref = MAY_LJMP(hlua_checkfunction(L, 3));
10076
Thierry Fournierf67442e2020-11-28 20:41:07 +010010077 /* Check for service already registered */
10078 trash = get_trash_chunk();
10079 chunk_printf(trash, "lua.%s", name);
10080 akw = service_find(trash->area);
10081 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010082 fcn = akw->private;
10083 if (fcn->function_ref[hlua_state_id] != -1) {
10084 ha_warning("Trying to register service 'lua.%s' more than once. "
10085 "This will become a hard error in version 2.5.\n", name);
10086 }
10087 fcn->function_ref[hlua_state_id] = ref;
10088 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010089 }
10090
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010091 /* Allocate and fill the sample fetch keyword struct. */
10092 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
10093 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010094 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010095 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010096 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010097 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010098
10099 /* Fill fcn. */
10100 len = strlen("<lua.>") + strlen(name) + 1;
10101 fcn->name = calloc(1, len);
10102 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010103 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010104 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +010010105 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010106
10107 /* List head */
10108 akl->list.n = akl->list.p = NULL;
10109
10110 /* converter keyword. */
10111 len = strlen("lua.") + strlen(name) + 1;
10112 akl->kw[0].kw = calloc(1, len);
10113 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010114 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010115
10116 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
10117
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +010010118 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010119 if (strcmp(env, "tcp") == 0)
10120 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010121 else if (strcmp(env, "http") == 0)
10122 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010123 else {
10124 release_hlua_function(fcn);
10125 if (akl)
10126 ha_free((char **)&(akl->kw[0].kw));
10127 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010010128 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +010010129 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +020010130 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010131
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020010132 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010133 akl->kw[0].private = fcn;
10134
10135 /* End of array. */
10136 memset(&akl->kw[1], 0, sizeof(*akl->kw));
10137
10138 /* Register this new converter */
10139 service_keywords_register(akl);
10140
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010141 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010142
10143 alloc_error:
10144 release_hlua_function(fcn);
10145 ha_free(&akl);
10146 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10147 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010148}
10149
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010150/* This function initialises Lua cli handler. It copies the
10151 * arguments in the Lua stack and create channel IO objects.
10152 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +020010153static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010154{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010155 struct hlua_cli_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010156 struct hlua *hlua;
10157 struct hlua_function *fcn;
10158 int i;
10159 const char *error;
10160
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010161 fcn = private;
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010162 ctx->fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010163
Willy Tarreaubafbe012017-11-24 17:34:44 +010010164 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010165 if (!hlua) {
10166 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010167 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010168 }
10169 HLUA_INIT(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010170 ctx->hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010171
10172 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +050010173 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010174 * applet_http. It is absolutely compatible.
10175 */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010176 ctx->task = task_new_here();
10177 if (!ctx->task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +010010178 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010179 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010180 }
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010181 ctx->task->nice = 0;
10182 ctx->task->context = appctx;
10183 ctx->task->process = hlua_applet_wakeup;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010184
10185 /* Initialises the Lua context */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010186 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), ctx->task, 0)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010187 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010188 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010189 }
10190
10191 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010192 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010193 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10194 error = lua_tostring(hlua->T, -1);
10195 else
10196 error = "critical error";
10197 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
10198 goto error;
10199 }
10200
10201 /* Check stack available size. */
10202 if (!lua_checkstack(hlua->T, 2)) {
10203 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10204 goto error;
10205 }
10206
10207 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +010010208 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010209
10210 /* Once the arguments parsed, the CLI is like an AppletTCP,
10211 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010212 */
10213 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
10214 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10215 goto error;
10216 }
10217 hlua->nargs = 1;
10218
10219 /* push keywords in the stack. */
10220 for (i = 0; *args[i]; i++) {
10221 /* Check stack available size. */
10222 if (!lua_checkstack(hlua->T, 1)) {
10223 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10224 goto error;
10225 }
10226 lua_pushstring(hlua->T, args[i]);
10227 hlua->nargs++;
10228 }
10229
10230 /* We must initialize the execution timeouts. */
10231 hlua->max_time = hlua_timeout_session;
10232
10233 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010234 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010235
10236 /* It's ok */
10237 return 0;
10238
10239 /* It's not ok. */
10240error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010241 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010242 hlua_ctx_destroy(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010243 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010244 return 1;
10245}
10246
10247static int hlua_cli_io_handler_fct(struct appctx *appctx)
10248{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010249 struct hlua_cli_ctx *ctx = appctx->svcctx;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010250 struct hlua *hlua;
Willy Tarreau475e4632022-05-27 10:26:46 +020010251 struct stconn *sc;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010252 struct hlua_function *fcn;
10253
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010254 hlua = ctx->hlua;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010255 sc = appctx_sc(appctx);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010256 fcn = ctx->fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010257
10258 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau475e4632022-05-27 10:26:46 +020010259 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010260 return 1;
10261
10262 /* Execute the function. */
10263 switch (hlua_ctx_resume(hlua, 1)) {
10264
10265 /* finished. */
10266 case HLUA_E_OK:
10267 return 1;
10268
10269 /* yield. */
10270 case HLUA_E_AGAIN:
10271 /* We want write. */
10272 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreau475e4632022-05-27 10:26:46 +020010273 sc_need_room(sc);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010274 /* Set the timeout. */
10275 if (hlua->wake_time != TICK_ETERNITY)
10276 task_schedule(hlua->task, hlua->wake_time);
10277 return 0;
10278
10279 /* finished with error. */
10280 case HLUA_E_ERRMSG:
10281 /* Display log. */
10282 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
10283 fcn->name, lua_tostring(hlua->T, -1));
10284 lua_pop(hlua->T, 1);
10285 return 1;
10286
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010287 case HLUA_E_ETMOUT:
10288 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
10289 fcn->name);
10290 return 1;
10291
10292 case HLUA_E_NOMEM:
10293 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
10294 fcn->name);
10295 return 1;
10296
10297 case HLUA_E_YIELD: /* unexpected */
10298 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
10299 fcn->name);
10300 return 1;
10301
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010302 case HLUA_E_ERR:
10303 /* Display log. */
10304 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
10305 fcn->name);
10306 return 1;
10307
10308 default:
10309 return 1;
10310 }
10311
10312 return 1;
10313}
10314
10315static void hlua_cli_io_release_fct(struct appctx *appctx)
10316{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010317 struct hlua_cli_ctx *ctx = appctx->svcctx;
10318
10319 hlua_ctx_destroy(ctx->hlua);
10320 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010321}
10322
10323/* This function is an LUA binding used for registering
10324 * new keywords in the cli. It expects a list of keywords
10325 * which are the "path". It is limited to 5 keywords. A
10326 * description of the command, a function to be executed
10327 * for the parsing and a function for io handlers.
10328 */
10329__LJMP static int hlua_register_cli(lua_State *L)
10330{
10331 struct cli_kw_list *cli_kws;
10332 const char *message;
10333 int ref_io;
10334 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010335 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010336 int index;
10337 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010338 struct buffer *trash;
10339 const char *kw[5];
10340 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010341 const char *errmsg;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010342
10343 MAY_LJMP(check_args(L, 3, "register_cli"));
10344
10345 /* First argument : an array of maximum 5 keywords. */
10346 if (!lua_istable(L, 1))
10347 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
10348
10349 /* Second argument : string with contextual message. */
10350 message = MAY_LJMP(luaL_checkstring(L, 2));
10351
10352 /* Third and fourth argument : lua function. */
10353 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
10354
Thierry Fournierf67442e2020-11-28 20:41:07 +010010355 /* Check for CLI service already registered */
10356 trash = get_trash_chunk();
10357 index = 0;
10358 lua_pushnil(L);
10359 memset(kw, 0, sizeof(kw));
10360 while (lua_next(L, 1) != 0) {
10361 if (index >= CLI_PREFIX_KW_NB)
10362 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
10363 if (lua_type(L, -1) != LUA_TSTRING)
10364 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
10365 kw[index] = lua_tostring(L, -1);
10366 if (index == 0)
10367 chunk_printf(trash, "%s", kw[index]);
10368 else
10369 chunk_appendf(trash, " %s", kw[index]);
10370 index++;
10371 lua_pop(L, 1);
10372 }
10373 cli_kw = cli_find_kw_exact((char **)kw);
10374 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010375 fcn = cli_kw->private;
10376 if (fcn->function_ref[hlua_state_id] != -1) {
10377 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
10378 "This will become a hard error in version 2.5.\n", trash->area);
10379 }
10380 fcn->function_ref[hlua_state_id] = ref_io;
10381 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010382 }
10383
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010384 /* Allocate and fill the sample fetch keyword struct. */
10385 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010386 if (!cli_kws) {
10387 errmsg = "Lua out of memory error.";
10388 goto error;
10389 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010390 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010391 if (!fcn) {
10392 errmsg = "Lua out of memory error.";
10393 goto error;
10394 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010395
10396 /* Fill path. */
10397 index = 0;
10398 lua_pushnil(L);
10399 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010400 if (index >= 5) {
10401 errmsg = "1st argument must be a table with a maximum of 5 entries";
10402 goto error;
10403 }
10404 if (lua_type(L, -1) != LUA_TSTRING) {
10405 errmsg = "1st argument must be a table filled with strings";
10406 goto error;
10407 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010408 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010409 if (!cli_kws->kw[0].str_kw[index]) {
10410 errmsg = "Lua out of memory error.";
10411 goto error;
10412 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010413 index++;
10414 lua_pop(L, 1);
10415 }
10416
10417 /* Copy help message. */
10418 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010419 if (!cli_kws->kw[0].usage) {
10420 errmsg = "Lua out of memory error.";
10421 goto error;
10422 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010423
10424 /* Fill fcn io handler. */
10425 len = strlen("<lua.cli>") + 1;
10426 for (i = 0; i < index; i++)
10427 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
10428 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010429 if (!fcn->name) {
10430 errmsg = "Lua out of memory error.";
10431 goto error;
10432 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010433 strncat((char *)fcn->name, "<lua.cli", len);
10434 for (i = 0; i < index; i++) {
10435 strncat((char *)fcn->name, ".", len);
10436 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
10437 }
10438 strncat((char *)fcn->name, ">", len);
Thierry Fournierc7492592020-11-28 23:57:24 +010010439 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010440
10441 /* Fill last entries. */
10442 cli_kws->kw[0].private = fcn;
10443 cli_kws->kw[0].parse = hlua_cli_parse_fct;
10444 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
10445 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
10446
10447 /* Register this new converter */
10448 cli_register_kw(cli_kws);
10449
10450 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010451
10452 error:
10453 release_hlua_function(fcn);
10454 if (cli_kws) {
10455 for (i = 0; i < index; i++)
10456 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
10457 ha_free((char **)&(cli_kws->kw[0].usage));
10458 }
10459 ha_free(&cli_kws);
10460 WILL_LJMP(luaL_error(L, errmsg));
10461 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010462}
10463
Christopher Faulet69c581a2021-05-31 08:54:04 +020010464static int hlua_filter_init_per_thread(struct proxy *px, struct flt_conf *fconf)
10465{
10466 struct hlua_flt_config *conf = fconf->conf;
10467 lua_State *L;
10468 int error, pos, state_id, flt_ref;
10469
10470 state_id = reg_flt_to_stack_id(conf->reg);
10471 L = hlua_states[state_id];
10472 pos = lua_gettop(L);
10473
10474 /* The filter parsing function */
10475 lua_rawgeti(L, LUA_REGISTRYINDEX, conf->reg->fun_ref[state_id]);
10476
10477 /* Push the filter class on the stack and resolve all callbacks */
10478 lua_rawgeti(L, LUA_REGISTRYINDEX, conf->reg->flt_ref[state_id]);
10479
10480 /* Duplicate the filter class so each filter will have its own copy */
10481 lua_newtable(L);
10482 lua_pushnil(L);
10483
10484 while (lua_next(L, pos+2)) {
10485 lua_pushvalue(L, -2);
10486 lua_insert(L, -2);
10487 lua_settable(L, -4);
10488 }
10489 flt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
10490
10491 /* Remove the original lua filter class from the stack */
10492 lua_pop(L, 1);
10493
10494 /* Push the copy on the stack */
10495 lua_rawgeti(L, LUA_REGISTRYINDEX, flt_ref);
10496
10497 /* extra args are pushed in a table */
10498 lua_newtable(L);
10499 for (pos = 0; conf->args[pos]; pos++) {
10500 /* Check stack available size. */
10501 if (!lua_checkstack(L, 1)) {
10502 ha_alert("Lua filter '%s' : Lua error : full stack.", conf->reg->name);
10503 goto error;
10504 }
10505 lua_pushstring(L, conf->args[pos]);
10506 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
10507 }
10508
10509 error = lua_pcall(L, 2, LUA_MULTRET, 0);
10510 switch (error) {
10511 case LUA_OK:
10512 /* replace the filter ref */
10513 conf->ref[state_id] = flt_ref;
10514 break;
10515 case LUA_ERRRUN:
10516 ha_alert("Lua filter '%s' : runtime error : %s", conf->reg->name, lua_tostring(L, -1));
10517 goto error;
10518 case LUA_ERRMEM:
10519 ha_alert("Lua filter '%s' : out of memory error", conf->reg->name);
10520 goto error;
10521 case LUA_ERRERR:
10522 ha_alert("Lua filter '%s' : message handler error : %s", conf->reg->name, lua_tostring(L, -1));
10523 goto error;
10524#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
10525 case LUA_ERRGCMM:
10526 ha_alert("Lua filter '%s' : garbage collector error : %s", conf->reg->name, lua_tostring(L, -1));
10527 goto error;
10528#endif
10529 default:
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050010530 ha_alert("Lua filter '%s' : unknown error : %s", conf->reg->name, lua_tostring(L, -1));
Christopher Faulet69c581a2021-05-31 08:54:04 +020010531 goto error;
10532 }
10533
10534 lua_settop(L, 0);
10535 return 0;
10536
10537 error:
10538 lua_settop(L, 0);
10539 return -1;
10540}
10541
10542static void hlua_filter_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
10543{
10544 struct hlua_flt_config *conf = fconf->conf;
10545 lua_State *L;
10546 int state_id;
10547
10548 if (!conf)
10549 return;
10550
10551 state_id = reg_flt_to_stack_id(conf->reg);
10552 L = hlua_states[state_id];
10553 luaL_unref(L, LUA_REGISTRYINDEX, conf->ref[state_id]);
10554}
10555
10556static int hlua_filter_init(struct proxy *px, struct flt_conf *fconf)
10557{
10558 struct hlua_flt_config *conf = fconf->conf;
10559 int state_id = reg_flt_to_stack_id(conf->reg);
10560
10561 /* Rely on per-thread init for global scripts */
10562 if (!state_id)
10563 return hlua_filter_init_per_thread(px, fconf);
10564 return 0;
10565}
10566
10567static void hlua_filter_deinit(struct proxy *px, struct flt_conf *fconf)
10568{
10569
10570 if (fconf->conf) {
10571 struct hlua_flt_config *conf = fconf->conf;
10572 int state_id = reg_flt_to_stack_id(conf->reg);
10573 int pos;
10574
10575 /* Rely on per-thread deinit for global scripts */
10576 if (!state_id)
10577 hlua_filter_deinit_per_thread(px, fconf);
10578
10579 for (pos = 0; conf->args[pos]; pos++)
10580 free(conf->args[pos]);
10581 free(conf->args);
10582 }
10583 ha_free(&fconf->conf);
10584 ha_free((char **)&fconf->id);
10585 ha_free(&fconf->ops);
10586}
10587
10588static int hlua_filter_new(struct stream *s, struct filter *filter)
10589{
10590 struct hlua_flt_config *conf = FLT_CONF(filter);
10591 struct hlua_flt_ctx *flt_ctx = NULL;
10592 int ret = 1;
10593
10594 /* In the execution wrappers linked with a stream, the
10595 * Lua context can be not initialized. This behavior
10596 * permits to save performances because a systematic
10597 * Lua initialization cause 5% performances loss.
10598 */
10599 if (!s->hlua) {
10600 struct hlua *hlua;
10601
10602 hlua = pool_alloc(pool_head_hlua);
10603 if (!hlua) {
10604 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
10605 conf->reg->name);
10606 ret = 0;
10607 goto end;
10608 }
10609 HLUA_INIT(hlua);
10610 s->hlua = hlua;
10611 if (!hlua_ctx_init(s->hlua, reg_flt_to_stack_id(conf->reg), s->task, 0)) {
10612 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
10613 conf->reg->name);
10614 ret = 0;
10615 goto end;
10616 }
10617 }
10618
10619 flt_ctx = pool_zalloc(pool_head_hlua_flt_ctx);
10620 if (!flt_ctx) {
10621 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10622 conf->reg->name);
10623 ret = 0;
10624 goto end;
10625 }
10626 flt_ctx->hlua[0] = pool_alloc(pool_head_hlua);
10627 flt_ctx->hlua[1] = pool_alloc(pool_head_hlua);
10628 if (!flt_ctx->hlua[0] || !flt_ctx->hlua[1]) {
10629 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10630 conf->reg->name);
10631 ret = 0;
10632 goto end;
10633 }
10634 HLUA_INIT(flt_ctx->hlua[0]);
10635 HLUA_INIT(flt_ctx->hlua[1]);
10636 if (!hlua_ctx_init(flt_ctx->hlua[0], reg_flt_to_stack_id(conf->reg), s->task, 0) ||
10637 !hlua_ctx_init(flt_ctx->hlua[1], reg_flt_to_stack_id(conf->reg), s->task, 0)) {
10638 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10639 conf->reg->name);
10640 ret = 0;
10641 goto end;
10642 }
10643
10644 if (!HLUA_IS_RUNNING(s->hlua)) {
10645 /* The following Lua calls can fail. */
10646 if (!SET_SAFE_LJMP(s->hlua)) {
10647 const char *error;
10648
10649 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
10650 error = lua_tostring(s->hlua->T, -1);
10651 else
10652 error = "critical error";
10653 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
10654 ret = 0;
10655 goto end;
10656 }
10657
10658 /* Check stack size. */
10659 if (!lua_checkstack(s->hlua->T, 1)) {
10660 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
Tim Duesterhus22817382021-09-11 23:17:25 +020010661 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010662 ret = 0;
10663 goto end;
10664 }
10665
10666 lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, conf->ref[s->hlua->state_id]);
10667 if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) {
10668 SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
10669 conf->reg->name);
10670 RESET_SAFE_LJMP(s->hlua);
10671 ret = 0;
10672 goto end;
10673 }
10674 lua_insert(s->hlua->T, -2);
10675
10676 /* Push the copy on the stack */
10677 s->hlua->nargs = 1;
10678
10679 /* We must initialize the execution timeouts. */
10680 s->hlua->max_time = hlua_timeout_session;
10681
10682 /* At this point the execution is safe. */
10683 RESET_SAFE_LJMP(s->hlua);
10684 }
10685
10686 switch (hlua_ctx_resume(s->hlua, 0)) {
10687 case HLUA_E_OK:
10688 /* Nothing returned or not a table, ignore the filter for current stream */
10689 if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) {
10690 ret = 0;
10691 goto end;
10692 }
10693
10694 /* Attached the filter pointer to the ctx */
10695 lua_pushstring(s->hlua->T, "__filter");
10696 lua_pushlightuserdata(s->hlua->T, filter);
10697 lua_settable(s->hlua->T, -3);
10698
10699 /* Save a ref on the filter ctx */
10700 lua_pushvalue(s->hlua->T, 1);
10701 flt_ctx->ref = luaL_ref(s->hlua->T, LUA_REGISTRYINDEX);
10702 filter->ctx = flt_ctx;
10703 break;
10704 case HLUA_E_ERRMSG:
10705 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(s->hlua->T, -1));
10706 ret = -1;
10707 goto end;
10708 case HLUA_E_ETMOUT:
10709 SEND_ERR(s->be, "Lua filter '%s' : 'new' execution timeout.\n", conf->reg->name);
10710 ret = 0;
10711 goto end;
10712 case HLUA_E_NOMEM:
10713 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
10714 ret = 0;
10715 goto end;
10716 case HLUA_E_AGAIN:
10717 case HLUA_E_YIELD:
10718 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
10719 " are not allowed from 'new' function.\n", conf->reg->name);
10720 ret = 0;
10721 goto end;
10722 case HLUA_E_ERR:
10723 SEND_ERR(s->be, "Lua filter '%s': 'new' returns an unknown error.\n", conf->reg->name);
10724 ret = 0;
10725 goto end;
10726 default:
10727 ret = 0;
10728 goto end;
10729 }
10730
10731 end:
10732 if (s->hlua)
10733 lua_settop(s->hlua->T, 0);
10734 if (ret <= 0) {
10735 if (flt_ctx) {
10736 hlua_ctx_destroy(flt_ctx->hlua[0]);
10737 hlua_ctx_destroy(flt_ctx->hlua[1]);
10738 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
10739 }
10740 }
10741 return ret;
10742}
10743
10744static void hlua_filter_delete(struct stream *s, struct filter *filter)
10745{
10746 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10747
10748 luaL_unref(s->hlua->T, LUA_REGISTRYINDEX, flt_ctx->ref);
10749 hlua_ctx_destroy(flt_ctx->hlua[0]);
10750 hlua_ctx_destroy(flt_ctx->hlua[1]);
10751 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
10752 filter->ctx = NULL;
10753}
10754
Christopher Faulet9f55a502020-02-25 15:21:02 +010010755static int hlua_filter_from_payload(struct filter *filter)
10756{
10757 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10758
10759 return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD));
10760}
10761
Christopher Fauletc404f112020-02-26 15:03:09 +010010762static int hlua_filter_callback(struct stream *s, struct filter *filter, const char *fun,
10763 int dir, unsigned int flags)
10764{
10765 struct hlua *flt_hlua;
10766 struct hlua_flt_config *conf = FLT_CONF(filter);
10767 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10768 unsigned int hflags = HLUA_TXN_FLT_CTX;
10769 int ret = 1;
10770
10771 flt_hlua = flt_ctx->hlua[(dir == SMP_OPT_DIR_REQ ? 0 : 1)];
10772 if (!flt_hlua)
10773 goto end;
10774
10775 if (!HLUA_IS_RUNNING(flt_hlua)) {
10776 int extra_idx = lua_gettop(flt_hlua->T);
10777
10778 /* The following Lua calls can fail. */
10779 if (!SET_SAFE_LJMP(flt_hlua)) {
10780 const char *error;
10781
10782 if (lua_type(flt_hlua->T, -1) == LUA_TSTRING)
10783 error = lua_tostring(flt_hlua->T, -1);
10784 else
10785 error = "critical error";
10786 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
10787 goto end;
10788 }
10789
10790 /* Check stack size. */
10791 if (!lua_checkstack(flt_hlua->T, 3)) {
10792 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10793 RESET_SAFE_LJMP(flt_hlua);
10794 goto end;
10795 }
10796
10797 lua_rawgeti(flt_hlua->T, LUA_REGISTRYINDEX, flt_ctx->ref);
10798 if (lua_getfield(flt_hlua->T, -1, fun) != LUA_TFUNCTION) {
10799 RESET_SAFE_LJMP(flt_hlua);
10800 goto end;
10801 }
10802 lua_insert(flt_hlua->T, -2);
10803
10804 if (!hlua_txn_new(flt_hlua->T, s, s->be, dir, hflags)) {
10805 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10806 RESET_SAFE_LJMP(flt_hlua);
10807 goto end;
10808 }
10809 flt_hlua->nargs = 2;
10810
10811 if (flags & HLUA_FLT_CB_ARG_CHN) {
10812 if (dir == SMP_OPT_DIR_REQ)
10813 lua_getfield(flt_hlua->T, -1, "req");
10814 else
10815 lua_getfield(flt_hlua->T, -1, "res");
10816 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
10817 lua_pushstring(flt_hlua->T, "__filter");
10818 lua_pushlightuserdata(flt_hlua->T, filter);
10819 lua_settable(flt_hlua->T, -3);
10820 }
10821 flt_hlua->nargs++;
10822 }
10823 else if (flags & HLUA_FLT_CB_ARG_HTTP_MSG) {
Christopher Fauleteae8afa2020-02-26 17:15:48 +010010824 if (dir == SMP_OPT_DIR_REQ)
10825 lua_getfield(flt_hlua->T, -1, "http_req");
10826 else
10827 lua_getfield(flt_hlua->T, -1, "http_res");
10828 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
10829 lua_pushstring(flt_hlua->T, "__filter");
10830 lua_pushlightuserdata(flt_hlua->T, filter);
10831 lua_settable(flt_hlua->T, -3);
10832 }
10833 flt_hlua->nargs++;
Christopher Fauletc404f112020-02-26 15:03:09 +010010834 }
10835
10836 /* Check stack size. */
10837 if (!lua_checkstack(flt_hlua->T, 1)) {
10838 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10839 RESET_SAFE_LJMP(flt_hlua);
10840 goto end;
10841 }
10842
10843 while (extra_idx--) {
10844 lua_pushvalue(flt_hlua->T, 1);
10845 lua_remove(flt_hlua->T, 1);
10846 flt_hlua->nargs++;
10847 }
10848
10849 /* We must initialize the execution timeouts. */
10850 flt_hlua->max_time = hlua_timeout_session;
10851
10852 /* At this point the execution is safe. */
10853 RESET_SAFE_LJMP(flt_hlua);
10854 }
10855
10856 switch (hlua_ctx_resume(flt_hlua, !(flags & HLUA_FLT_CB_FINAL))) {
10857 case HLUA_E_OK:
10858 /* Catch the return value if it required */
10859 if ((flags & HLUA_FLT_CB_RETVAL) && lua_gettop(flt_hlua->T) > 0) {
10860 ret = lua_tointeger(flt_hlua->T, -1);
10861 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
10862 }
10863
10864 /* Set timeout in the required channel. */
10865 if (flt_hlua->wake_time != TICK_ETERNITY) {
10866 if (dir == SMP_OPT_DIR_REQ)
10867 s->req.analyse_exp = flt_hlua->wake_time;
10868 else
10869 s->res.analyse_exp = flt_hlua->wake_time;
10870 }
10871 break;
10872 case HLUA_E_AGAIN:
10873 /* Set timeout in the required channel. */
10874 if (flt_hlua->wake_time != TICK_ETERNITY) {
10875 if (dir == SMP_OPT_DIR_REQ)
10876 s->req.analyse_exp = flt_hlua->wake_time;
10877 else
10878 s->res.analyse_exp = flt_hlua->wake_time;
10879 }
10880 /* Some actions can be wake up when a "write" event
10881 * is detected on a response channel. This is useful
10882 * only for actions targeted on the requests.
10883 */
10884 if (HLUA_IS_WAKERESWR(flt_hlua))
10885 s->res.flags |= CF_WAKE_WRITE;
10886 if (HLUA_IS_WAKEREQWR(flt_hlua))
10887 s->req.flags |= CF_WAKE_WRITE;
10888 ret = 0;
10889 goto end;
10890 case HLUA_E_ERRMSG:
10891 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(flt_hlua->T, -1));
10892 ret = -1;
10893 goto end;
10894 case HLUA_E_ETMOUT:
10895 SEND_ERR(s->be, "Lua filter '%s' : '%s' callback execution timeout.\n", conf->reg->name, fun);
10896 goto end;
10897 case HLUA_E_NOMEM:
10898 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
10899 goto end;
10900 case HLUA_E_YIELD:
10901 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
10902 " are not allowed from '%s' callback.\n", conf->reg->name, fun);
10903 goto end;
10904 case HLUA_E_ERR:
10905 SEND_ERR(s->be, "Lua filter '%s': '%s' returns an unknown error.\n", conf->reg->name, fun);
10906 goto end;
10907 default:
10908 goto end;
10909 }
10910
10911
10912 end:
10913 return ret;
10914}
10915
10916static int hlua_filter_start_analyze(struct stream *s, struct filter *filter, struct channel *chn)
10917{
10918 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10919
10920 flt_ctx->flags = 0;
10921 return hlua_filter_callback(s, filter, "start_analyze",
10922 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10923 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
10924}
10925
10926static int hlua_filter_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
10927{
10928 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10929
10930 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
10931 return hlua_filter_callback(s, filter, "end_analyze",
10932 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10933 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
10934}
10935
Christopher Fauleteae8afa2020-02-26 17:15:48 +010010936static int hlua_filter_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
10937{
10938 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10939
10940 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
10941 return hlua_filter_callback(s, filter, "http_headers",
10942 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10943 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
10944}
10945
10946static int hlua_filter_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
10947 unsigned int offset, unsigned int len)
10948{
10949 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10950 struct hlua *flt_hlua;
10951 int dir = (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
10952 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
10953 int ret;
10954
10955 flt_hlua = flt_ctx->hlua[idx];
10956 flt_ctx->cur_off[idx] = offset;
10957 flt_ctx->cur_len[idx] = len;
10958 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
10959 ret = hlua_filter_callback(s, filter, "http_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_HTTP_MSG));
10960 if (ret != -1) {
10961 ret = flt_ctx->cur_len[idx];
10962 if (lua_gettop(flt_hlua->T) > 0) {
10963 ret = lua_tointeger(flt_hlua->T, -1);
10964 if (ret > flt_ctx->cur_len[idx])
10965 ret = flt_ctx->cur_len[idx];
10966 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
10967 }
10968 }
10969 return ret;
10970}
10971
10972static int hlua_filter_http_end(struct stream *s, struct filter *filter, struct http_msg *msg)
10973{
10974 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10975
10976 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
10977 return hlua_filter_callback(s, filter, "http_end",
10978 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10979 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
10980}
10981
Christopher Fauletc404f112020-02-26 15:03:09 +010010982static int hlua_filter_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
10983 unsigned int offset, unsigned int len)
10984{
10985 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10986 struct hlua *flt_hlua;
10987 int dir = (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
10988 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
10989 int ret;
10990
10991 flt_hlua = flt_ctx->hlua[idx];
10992 flt_ctx->cur_off[idx] = offset;
10993 flt_ctx->cur_len[idx] = len;
10994 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
10995 ret = hlua_filter_callback(s, filter, "tcp_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_CHN));
10996 if (ret != -1) {
10997 ret = flt_ctx->cur_len[idx];
10998 if (lua_gettop(flt_hlua->T) > 0) {
10999 ret = lua_tointeger(flt_hlua->T, -1);
11000 if (ret > flt_ctx->cur_len[idx])
11001 ret = flt_ctx->cur_len[idx];
11002 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11003 }
11004 }
11005 return ret;
11006}
11007
Christopher Faulet69c581a2021-05-31 08:54:04 +020011008static int hlua_filter_parse_fct(char **args, int *cur_arg, struct proxy *px,
11009 struct flt_conf *fconf, char **err, void *private)
11010{
11011 struct hlua_reg_filter *reg_flt = private;
11012 lua_State *L;
11013 struct hlua_flt_config *conf = NULL;
11014 const char *flt_id = NULL;
11015 int state_id, pos, flt_flags = 0;
11016 struct flt_ops *hlua_flt_ops = NULL;
11017
11018 state_id = reg_flt_to_stack_id(reg_flt);
11019 L = hlua_states[state_id];
11020
11021 /* Initialize the filter ops with default callbacks */
11022 hlua_flt_ops = calloc(1, sizeof(*hlua_flt_ops));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011023 if (!hlua_flt_ops)
11024 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011025 hlua_flt_ops->init = hlua_filter_init;
11026 hlua_flt_ops->deinit = hlua_filter_deinit;
11027 if (state_id) {
11028 /* Set per-thread callback if script is loaded per-thread */
11029 hlua_flt_ops->init_per_thread = hlua_filter_init_per_thread;
11030 hlua_flt_ops->deinit_per_thread = hlua_filter_deinit_per_thread;
11031 }
11032 hlua_flt_ops->attach = hlua_filter_new;
11033 hlua_flt_ops->detach = hlua_filter_delete;
11034
11035 /* Push the filter class on the stack and resolve all callbacks */
11036 lua_rawgeti(L, LUA_REGISTRYINDEX, reg_flt->flt_ref[state_id]);
11037
Christopher Fauletc404f112020-02-26 15:03:09 +010011038 if (lua_getfield(L, -1, "start_analyze") == LUA_TFUNCTION)
11039 hlua_flt_ops->channel_start_analyze = hlua_filter_start_analyze;
11040 lua_pop(L, 1);
11041 if (lua_getfield(L, -1, "end_analyze") == LUA_TFUNCTION)
11042 hlua_flt_ops->channel_end_analyze = hlua_filter_end_analyze;
11043 lua_pop(L, 1);
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011044 if (lua_getfield(L, -1, "http_headers") == LUA_TFUNCTION)
11045 hlua_flt_ops->http_headers = hlua_filter_http_headers;
11046 lua_pop(L, 1);
11047 if (lua_getfield(L, -1, "http_payload") == LUA_TFUNCTION)
11048 hlua_flt_ops->http_payload = hlua_filter_http_payload;
11049 lua_pop(L, 1);
11050 if (lua_getfield(L, -1, "http_end") == LUA_TFUNCTION)
11051 hlua_flt_ops->http_end = hlua_filter_http_end;
11052 lua_pop(L, 1);
Christopher Fauletc404f112020-02-26 15:03:09 +010011053 if (lua_getfield(L, -1, "tcp_payload") == LUA_TFUNCTION)
11054 hlua_flt_ops->tcp_payload = hlua_filter_tcp_payload;
11055 lua_pop(L, 1);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011056
11057 /* Get id and flags of the filter class */
11058 if (lua_getfield(L, -1, "id") == LUA_TSTRING)
11059 flt_id = lua_tostring(L, -1);
11060 lua_pop(L, 1);
11061 if (lua_getfield(L, -1, "flags") == LUA_TNUMBER)
11062 flt_flags = lua_tointeger(L, -1);
11063 lua_pop(L, 1);
11064
11065 /* Create the filter config */
11066 conf = calloc(1, sizeof(*conf));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011067 if (!conf)
Christopher Faulet69c581a2021-05-31 08:54:04 +020011068 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011069 conf->reg = reg_flt;
11070
11071 /* duplicate args */
11072 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++);
11073 conf->args = calloc(pos + 1, sizeof(*conf->args));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011074 if (!conf->args)
11075 goto error;
11076 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020011077 conf->args[pos] = strdup(args[*cur_arg + 1 + pos]);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011078 if (!conf->args[pos])
11079 goto error;
11080 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011081 conf->args[pos] = NULL;
11082 *cur_arg += pos + 1;
11083
Christopher Fauletc86bb872021-08-13 08:33:57 +020011084 if (flt_id) {
11085 fconf->id = strdup(flt_id);
11086 if (!fconf->id)
11087 goto error;
11088 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011089 fconf->flags = flt_flags;
11090 fconf->conf = conf;
11091 fconf->ops = hlua_flt_ops;
11092
11093 lua_settop(L, 0);
11094 return 0;
11095
11096 error:
Christopher Fauletc86bb872021-08-13 08:33:57 +020011097 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011098 free(hlua_flt_ops);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011099 if (conf && conf->args) {
11100 for (pos = 0; conf->args[pos]; pos++)
11101 free(conf->args[pos]);
11102 free(conf->args);
11103 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011104 free(conf);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011105 free((char *)fconf->id);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011106 lua_settop(L, 0);
11107 return -1;
11108}
11109
Christopher Fauletc404f112020-02-26 15:03:09 +010011110__LJMP static int hlua_register_data_filter(lua_State *L)
11111{
11112 struct filter *filter;
11113 struct channel *chn;
11114
11115 MAY_LJMP(check_args(L, 2, "register_data_filter"));
11116 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
11117 chn = MAY_LJMP(hlua_checkchannel(L, 2));
11118
11119 lua_getfield(L, 1, "__filter");
11120 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
11121 filter = lua_touserdata (L, -1);
11122 lua_pop(L, 1);
11123
11124 register_data_filter(chn_strm(chn), chn, filter);
11125 return 1;
11126}
11127
11128__LJMP static int hlua_unregister_data_filter(lua_State *L)
11129{
11130 struct filter *filter;
11131 struct channel *chn;
11132
11133 MAY_LJMP(check_args(L, 2, "unregister_data_filter"));
11134 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
11135 chn = MAY_LJMP(hlua_checkchannel(L, 2));
11136
11137 lua_getfield(L, 1, "__filter");
11138 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
11139 filter = lua_touserdata (L, -1);
11140 lua_pop(L, 1);
11141
11142 unregister_data_filter(chn_strm(chn), chn, filter);
11143 return 1;
11144}
11145
Christopher Faulet69c581a2021-05-31 08:54:04 +020011146/* This function is an LUA binding used for registering a filter. It expects a
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050011147 * filter name used in the haproxy configuration file and a LUA function to
Christopher Faulet69c581a2021-05-31 08:54:04 +020011148 * parse configuration arguments.
11149 */
11150__LJMP static int hlua_register_filter(lua_State *L)
11151{
11152 struct buffer *trash;
11153 struct flt_kw_list *fkl;
11154 struct flt_kw *fkw;
11155 const char *name;
11156 struct hlua_reg_filter *reg_flt= NULL;
11157 int flt_ref, fun_ref;
11158 int len;
11159
11160 MAY_LJMP(check_args(L, 3, "register_filter"));
11161
11162 /* First argument : filter name. */
11163 name = MAY_LJMP(luaL_checkstring(L, 1));
11164
11165 /* Second argument : The filter class */
11166 flt_ref = MAY_LJMP(hlua_checktable(L, 2));
11167
11168 /* Third argument : lua function. */
11169 fun_ref = MAY_LJMP(hlua_checkfunction(L, 3));
11170
11171 trash = get_trash_chunk();
11172 chunk_printf(trash, "lua.%s", name);
11173 fkw = flt_find_kw(trash->area);
11174 if (fkw != NULL) {
11175 reg_flt = fkw->private;
11176 if (reg_flt->flt_ref[hlua_state_id] != -1 || reg_flt->fun_ref[hlua_state_id] != -1) {
11177 ha_warning("Trying to register filter 'lua.%s' more than once. "
11178 "This will become a hard error in version 2.5.\n", name);
11179 }
11180 reg_flt->flt_ref[hlua_state_id] = flt_ref;
11181 reg_flt->fun_ref[hlua_state_id] = fun_ref;
11182 return 0;
11183 }
11184
11185 fkl = calloc(1, sizeof(*fkl) + sizeof(struct flt_kw) * 2);
11186 if (!fkl)
11187 goto alloc_error;
11188 fkl->scope = "HLUA";
11189
11190 reg_flt = new_hlua_reg_filter(name);
11191 if (!reg_flt)
11192 goto alloc_error;
11193
11194 reg_flt->flt_ref[hlua_state_id] = flt_ref;
11195 reg_flt->fun_ref[hlua_state_id] = fun_ref;
11196
11197 /* The filter keyword */
11198 len = strlen("lua.") + strlen(name) + 1;
11199 fkl->kw[0].kw = calloc(1, len);
11200 if (!fkl->kw[0].kw)
11201 goto alloc_error;
11202
11203 snprintf((char *)fkl->kw[0].kw, len, "lua.%s", name);
11204
11205 fkl->kw[0].parse = hlua_filter_parse_fct;
11206 fkl->kw[0].private = reg_flt;
11207 memset(&fkl->kw[1], 0, sizeof(*fkl->kw));
11208
11209 /* Register this new filter */
11210 flt_register_keywords(fkl);
11211
11212 return 0;
11213
11214 alloc_error:
11215 release_hlua_reg_filter(reg_flt);
11216 ha_free(&fkl);
11217 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11218 return 0; /* Never reached */
11219}
11220
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011221static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011222 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011223 char **err, unsigned int *timeout)
11224{
11225 const char *error;
11226
11227 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +020011228 if (error == PARSE_TIME_OVER) {
11229 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
11230 args[1], args[0]);
11231 return -1;
11232 }
11233 else if (error == PARSE_TIME_UNDER) {
11234 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
11235 args[1], args[0]);
11236 return -1;
11237 }
11238 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011239 memprintf(err, "%s: invalid timeout", args[0]);
11240 return -1;
11241 }
11242 return 0;
11243}
11244
11245static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011246 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011247 char **err)
11248{
11249 return hlua_read_timeout(args, section_type, curpx, defpx,
11250 file, line, err, &hlua_timeout_session);
11251}
11252
11253static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011254 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011255 char **err)
11256{
11257 return hlua_read_timeout(args, section_type, curpx, defpx,
11258 file, line, err, &hlua_timeout_task);
11259}
11260
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011261static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011262 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011263 char **err)
11264{
11265 return hlua_read_timeout(args, section_type, curpx, defpx,
11266 file, line, err, &hlua_timeout_applet);
11267}
11268
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011269static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011270 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011271 char **err)
11272{
11273 char *error;
11274
11275 hlua_nb_instruction = strtoll(args[1], &error, 10);
11276 if (*error != '\0') {
11277 memprintf(err, "%s: invalid number", args[0]);
11278 return -1;
11279 }
11280 return 0;
11281}
11282
Willy Tarreau32f61e22015-03-18 17:54:59 +010011283static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011284 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +010011285 char **err)
11286{
11287 char *error;
11288
11289 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011290 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).", args[0]);
Willy Tarreau32f61e22015-03-18 17:54:59 +010011291 return -1;
11292 }
11293 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
11294 if (*error != '\0') {
11295 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
11296 return -1;
11297 }
11298 return 0;
11299}
11300
11301
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011302/* This function is called by the main configuration key "lua-load". It loads and
11303 * execute an lua file during the parsing of the HAProxy configuration file. It is
11304 * the main lua entry point.
11305 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080011306 * This function runs with the HAProxy keywords API. It returns -1 if an error
11307 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011308 *
11309 * In some error case, LUA set an error message in top of the stack. This function
11310 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020011311 *
11312 * This function can fail with an abort() due to an Lua critical error.
11313 * We are in the configuration parsing process of HAProxy, this abort() is
11314 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011315 */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011316static int hlua_load_state(char **args, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011317{
11318 int error;
Thierry Fournierae6b5682022-09-19 09:04:16 +020011319 int nargs;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011320
11321 /* Just load and compile the file. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011322 error = luaL_loadfile(L, args[0]);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011323 if (error) {
Thierry Fournierae6b5682022-09-19 09:04:16 +020011324 memprintf(err, "error in Lua file '%s': %s", args[0], lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011325 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011326 return -1;
11327 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011328
11329 /* Push args in the Lua stack, except the first one which is the filename */
11330 for (nargs = 1; *(args[nargs]) != 0; nargs++) {
Aurelien DARRAGON4d7aefe2022-09-23 10:22:14 +020011331 /* Check stack size. */
11332 if (!lua_checkstack(L, 1)) {
11333 memprintf(err, "Lua runtime error while loading arguments: stack is full.");
11334 return -1;
11335 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011336 lua_pushstring(L, args[nargs]);
11337 }
11338 nargs--;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011339
11340 /* If no syntax error where detected, execute the code. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011341 error = lua_pcall(L, nargs, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011342 switch (error) {
11343 case LUA_OK:
11344 break;
11345 case LUA_ERRRUN:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011346 memprintf(err, "Lua runtime error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011347 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011348 return -1;
11349 case LUA_ERRMEM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011350 memprintf(err, "Lua out of memory error");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011351 return -1;
11352 case LUA_ERRERR:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011353 memprintf(err, "Lua message handler error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011354 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011355 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020011356#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011357 case LUA_ERRGCMM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011358 memprintf(err, "Lua garbage collector error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011359 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011360 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020011361#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011362 default:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011363 memprintf(err, "Lua unknown error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011364 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011365 return -1;
11366 }
11367
11368 return 0;
11369}
11370
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011371static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011372 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011373 char **err)
11374{
11375 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011376 memprintf(err, "'%s' expects a file name as parameter.", args[0]);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011377 return -1;
11378 }
11379
Thierry Fournier59f11be2020-11-29 00:37:41 +010011380 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +010011381 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011382 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020011383 return hlua_load_state(&args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011384}
11385
Thierry Fournier59f11be2020-11-29 00:37:41 +010011386static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011387 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +010011388 char **err)
11389{
11390 int len;
Thierry Fournierae6b5682022-09-19 09:04:16 +020011391 int i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011392
11393 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011394 memprintf(err, "'%s' expects a file as parameter.", args[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011395 return -1;
11396 }
11397
11398 if (per_thread_load == NULL) {
11399 /* allocate the first entry large enough to store the final NULL */
11400 per_thread_load = calloc(1, sizeof(*per_thread_load));
11401 if (per_thread_load == NULL) {
11402 memprintf(err, "out of memory error");
11403 return -1;
11404 }
11405 }
11406
11407 /* count used entries */
11408 for (len = 0; per_thread_load[len] != NULL; len++)
11409 ;
11410
11411 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
11412 if (per_thread_load == NULL) {
11413 memprintf(err, "out of memory error");
11414 return -1;
11415 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010011416 per_thread_load[len + 1] = NULL;
11417
Thierry Fournierae6b5682022-09-19 09:04:16 +020011418 /* count args excepting the first, allocate array and copy args */
11419 for (i = 0; *(args[i + 1]) != 0; i++);
Aurelien DARRAGONb12d1692022-09-23 08:48:34 +020011420 per_thread_load[len] = calloc(i + 1, sizeof(*per_thread_load[len]));
Thierry Fournier59f11be2020-11-29 00:37:41 +010011421 if (per_thread_load[len] == NULL) {
11422 memprintf(err, "out of memory error");
11423 return -1;
11424 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011425 for (i = 1; *(args[i]) != 0; i++) {
11426 per_thread_load[len][i - 1] = strdup(args[i]);
11427 if (per_thread_load[len][i - 1] == NULL) {
11428 memprintf(err, "out of memory error");
11429 return -1;
11430 }
11431 }
11432 per_thread_load[len][i - 1] = strdup("");
11433 if (per_thread_load[len][i - 1] == NULL) {
11434 memprintf(err, "out of memory error");
11435 return -1;
11436 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010011437
11438 /* loading for thread 1 only */
11439 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011440 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020011441 return hlua_load_state(per_thread_load[len], hlua_states[1], err);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011442}
11443
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011444/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
11445 * in the given <ctx>.
11446 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +010011447static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011448{
Thierry Fournier3fb9e512020-11-28 10:13:12 +010011449 lua_getglobal(L, "package"); /* push package variable */
11450 lua_pushstring(L, path); /* push given path */
11451 lua_pushstring(L, ";"); /* push semicolon */
11452 lua_getfield(L, -3, type); /* push old path */
11453 lua_concat(L, 3); /* concatenate to new path */
11454 lua_setfield(L, -2, type); /* store new path */
11455 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011456
11457 return 0;
11458}
11459
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011460static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011461 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011462 char **err)
11463{
11464 char *path;
11465 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011466 struct prepend_path *p = NULL;
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000011467 size_t i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011468
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011469 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011470 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011471 }
11472
11473 if (!(*args[1])) {
11474 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011475 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011476 }
11477 path = args[1];
11478
11479 if (*args[2]) {
11480 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
11481 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011482 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011483 }
11484 type = args[2];
11485 }
11486
Thierry Fournier59f11be2020-11-29 00:37:41 +010011487 p = calloc(1, sizeof(*p));
11488 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011489 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011490 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011491 }
11492 p->path = strdup(path);
11493 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011494 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011495 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011496 }
11497 p->type = strdup(type);
11498 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011499 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011500 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011501 }
Willy Tarreau2b718102021-04-21 07:32:39 +020011502 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011503
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020011504 /* Handle the global state and the per-thread state for the first
11505 * thread. The remaining threads will be initialized based on
11506 * prepend_path_list.
11507 */
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000011508 for (i = 0; i < 2; i++) {
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020011509 lua_State *L = hlua_states[i];
11510 const char *error;
11511
11512 if (setjmp(safe_ljmp_env) != 0) {
11513 lua_atpanic(L, hlua_panic_safe);
11514 if (lua_type(L, -1) == LUA_TSTRING)
11515 error = lua_tostring(L, -1);
11516 else
11517 error = "critical error";
11518 fprintf(stderr, "lua-prepend-path: %s.\n", error);
11519 exit(1);
11520 } else {
11521 lua_atpanic(L, hlua_panic_ljmp);
11522 }
11523
11524 hlua_prepend_path(L, type, path);
11525
11526 lua_atpanic(L, hlua_panic_safe);
11527 }
11528
Thierry Fournier59f11be2020-11-29 00:37:41 +010011529 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011530
11531err2:
11532 free(p->type);
11533 free(p->path);
11534err:
11535 free(p);
11536 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011537}
11538
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011539/* configuration keywords declaration */
11540static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011541 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011542 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +010011543 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011544 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
11545 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +020011546 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011547 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +010011548 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011549 { 0, NULL, NULL },
11550}};
11551
Willy Tarreau0108d902018-11-25 19:14:37 +010011552INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
11553
William Lallemand52139182022-03-30 15:05:42 +020011554#ifdef USE_OPENSSL
Christopher Fauletafd8f102018-11-08 11:34:21 +010011555
William Lallemand30fcca12022-03-30 12:03:12 +020011556/*
11557 * This function replace a ckch_store by another one, and rebuild the ckch_inst and all its dependencies.
11558 * It does the sam as "cli_io_handler_commit_cert" but for lua, the major
11559 * difference is that the yield in lua and for the CLI is not handled the same
11560 * way.
11561 */
11562__LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext ctx)
11563{
11564 struct ckch_inst **lua_ckchi = lua_touserdata(L, -1);
11565 struct ckch_store **lua_ckchs = lua_touserdata(L, -2);
11566 struct ckch_inst *ckchi = *lua_ckchi;
11567 struct ckch_store *old_ckchs = lua_ckchs[0];
11568 struct ckch_store *new_ckchs = lua_ckchs[1];
11569 struct hlua *hlua;
11570 char *err = NULL;
11571 int y = 1;
11572
11573 hlua = hlua_gethlua(L);
11574
11575 /* get the first ckchi to copy */
11576 if (ckchi == NULL)
11577 ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
11578
11579 /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
11580 list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
11581 struct ckch_inst *new_inst;
11582
11583 /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
11584 if (y % 10 == 0) {
11585
11586 *lua_ckchi = ckchi;
11587
11588 task_wakeup(hlua->task, TASK_WOKEN_MSG);
11589 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
11590 }
11591
11592 if (ckch_inst_rebuild(new_ckchs, ckchi, &new_inst, &err))
11593 goto error;
11594
11595 /* link the new ckch_inst to the duplicate */
11596 LIST_APPEND(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
11597 y++;
11598 }
11599
11600 /* The generation is finished, we can insert everything */
11601 ckch_store_replace(old_ckchs, new_ckchs);
11602
11603 lua_pop(L, 2); /* pop the lua_ckchs and ckchi */
11604
11605 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11606
11607 return 0;
11608
11609error:
11610 ckch_store_free(new_ckchs);
11611 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11612 WILL_LJMP(luaL_error(L, "%s", err));
11613 free(err);
11614
11615 return 0;
11616}
11617
11618/*
11619 * Replace a ckch_store <filename> in the ckchs_tree with a ckch_store created
11620 * from the table in parameter.
11621 *
11622 * This is equivalent to "set ssl cert" + "commit ssl cert" over the CLI, which
11623 * means it does not need to have a transaction since everything is done in the
11624 * same function.
11625 *
11626 * CertCache.set{filename="", crt="", key="", sctl="", ocsp="", issuer=""}
11627 *
11628 */
11629__LJMP static int hlua_ckch_set(lua_State *L)
11630{
11631 struct hlua *hlua;
11632 struct ckch_inst **lua_ckchi;
11633 struct ckch_store **lua_ckchs;
11634 struct ckch_store *old_ckchs = NULL;
11635 struct ckch_store *new_ckchs = NULL;
11636 int errcode = 0;
11637 char *err = NULL;
11638 struct cert_exts *cert_ext = NULL;
11639 char *filename;
William Lallemand52ddd992022-11-22 11:51:53 +010011640 struct ckch_data *data;
William Lallemand30fcca12022-03-30 12:03:12 +020011641 int ret;
11642
11643 if (lua_type(L, -1) != LUA_TTABLE)
11644 WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
11645
11646 hlua = hlua_gethlua(L);
11647
11648 /* FIXME: this should not return an error but should come back later */
11649 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
11650 WILL_LJMP(luaL_error(L, "CertCache already under lock"));
11651
11652 ret = lua_getfield(L, -1, "filename");
11653 if (ret != LUA_TSTRING) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011654 memprintf(&err, "%sNo filename specified!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011655 errcode |= ERR_ALERT | ERR_FATAL;
11656 goto end;
11657 }
11658 filename = (char *)lua_tostring(L, -1);
11659
11660
11661 /* look for the filename in the tree */
11662 old_ckchs = ckchs_lookup(filename);
11663 if (!old_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011664 memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011665 errcode |= ERR_ALERT | ERR_FATAL;
11666 goto end;
11667 }
11668 /* TODO: handle extra_files_noext */
11669
11670 new_ckchs = ckchs_dup(old_ckchs);
11671 if (!new_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011672 memprintf(&err, "%sCannot allocate memory!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011673 errcode |= ERR_ALERT | ERR_FATAL;
11674 goto end;
11675 }
11676
William Lallemand52ddd992022-11-22 11:51:53 +010011677 data = new_ckchs->data;
William Lallemand30fcca12022-03-30 12:03:12 +020011678
11679 /* loop on the field in the table, which have the same name as the
11680 * possible extensions of files */
11681 lua_pushnil(L);
11682 while (lua_next(L, 1)) {
11683 int i;
11684 const char *field = lua_tostring(L, -2);
11685 char *payload = (char *)lua_tostring(L, -1);
11686
11687 if (!field || strcmp(field, "filename") == 0) {
11688 lua_pop(L, 1);
11689 continue;
11690 }
11691
11692 for (i = 0; field && cert_exts[i].ext != NULL; i++) {
11693 if (strcmp(field, cert_exts[i].ext) == 0) {
11694 cert_ext = &cert_exts[i];
11695 break;
11696 }
11697 }
11698
11699 /* this is the default type, the field is not supported */
11700 if (cert_ext == NULL) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011701 memprintf(&err, "%sUnsupported field '%s'", err ? err : "", field);
William Lallemand30fcca12022-03-30 12:03:12 +020011702 errcode |= ERR_ALERT | ERR_FATAL;
11703 goto end;
11704 }
11705
11706 /* appply the change on the duplicate */
William Lallemand52ddd992022-11-22 11:51:53 +010011707 if (cert_ext->load(filename, payload, data, &err) != 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011708 memprintf(&err, "%sCan't load the payload for '%s'", err ? err : "", cert_ext->ext);
William Lallemand30fcca12022-03-30 12:03:12 +020011709 errcode |= ERR_ALERT | ERR_FATAL;
11710 goto end;
11711 }
11712 lua_pop(L, 1);
11713 }
11714
11715 /* store the pointers on the lua stack */
11716 lua_ckchs = lua_newuserdata(L, sizeof(struct ckch_store *) * 2);
11717 lua_ckchs[0] = old_ckchs;
11718 lua_ckchs[1] = new_ckchs;
11719 lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
11720 *lua_ckchi = NULL;
11721
11722 task_wakeup(hlua->task, TASK_WOKEN_MSG);
11723 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
11724
11725end:
11726 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11727
11728 if (errcode & ERR_CODE) {
11729 ckch_store_free(new_ckchs);
11730 WILL_LJMP(luaL_error(L, "%s", err));
11731 }
11732 free(err);
11733
11734 return 0;
11735}
11736
William Lallemand52139182022-03-30 15:05:42 +020011737#else
11738
11739__LJMP static int hlua_ckch_set(lua_State *L)
11740{
11741 WILL_LJMP(luaL_error(L, "'CertCache.set' needs an HAProxy built with OpenSSL"));
11742
11743 return 0;
11744}
11745#endif /* ! USE_OPENSSL */
11746
11747
11748
Thierry FOURNIERbabae282015-09-17 11:36:37 +020011749/* This function can fail with an abort() due to an Lua critical error.
11750 * We are in the initialisation process of HAProxy, this abort() is
11751 * tolerated.
11752 */
Thierry Fournierb8cef172020-11-28 15:37:17 +010011753int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011754{
11755 struct hlua_init_function *init;
11756 const char *msg;
11757 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +010011758 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +010011759 const char *kind;
11760 const char *trace;
11761 int return_status = 1;
11762#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
11763 int nres;
11764#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011765
Willy Tarreaucdb53462020-12-02 12:12:00 +010011766 /* disable memory limit checks if limit is not set */
11767 if (!hlua_global_allocator.limit)
11768 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
11769
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050011770 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +010011771 if (setjmp(safe_ljmp_env) != 0) {
11772 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +010011773 if (lua_type(L, -1) == LUA_TSTRING)
11774 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011775 else
11776 error = "critical error";
11777 fprintf(stderr, "Lua post-init: %s.\n", error);
11778 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010011779 } else {
11780 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011781 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +020011782
Thierry Fournierb8cef172020-11-28 15:37:17 +010011783 hlua_fcn_post_init(L);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011784
Thierry Fournierc7492592020-11-28 23:57:24 +010011785 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010011786 lua_rawgeti(L, LUA_REGISTRYINDEX, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +010011787
11788#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +010011789 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +010011790#else
Thierry Fournierb8cef172020-11-28 15:37:17 +010011791 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +010011792#endif
11793 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011794 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +010011795
11796 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +010011797 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +010011798 break;
Thierry Fournier670db242020-11-28 10:49:59 +010011799
11800 case LUA_ERRERR:
11801 kind = "message handler error";
Willy Tarreau14de3952022-11-14 07:08:28 +010011802 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011803 case LUA_ERRRUN:
11804 if (!kind)
11805 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010011806 msg = lua_tostring(L, -1);
11807 lua_settop(L, 0); /* Empty the stack. */
11808 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +010011809 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010011810 if (msg)
11811 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
11812 else
11813 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
11814 return_status = 0;
11815 break;
11816
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011817 default:
Thierry Fournier670db242020-11-28 10:49:59 +010011818 /* Unknown error */
11819 kind = "Unknown error";
Willy Tarreau14de3952022-11-14 07:08:28 +010011820 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011821 case LUA_YIELD:
11822 /* yield is not configured at this step, this state doesn't happen */
11823 if (!kind)
11824 kind = "yield not allowed";
Willy Tarreau14de3952022-11-14 07:08:28 +010011825 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011826 case LUA_ERRMEM:
11827 if (!kind)
11828 kind = "out of memory error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010011829 lua_settop(L, 0);
11830 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +010011831 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010011832 ha_alert("Lua init: %s: %s\n", kind, trace);
11833 return_status = 0;
11834 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011835 }
Thierry Fournier670db242020-11-28 10:49:59 +010011836 if (!return_status)
11837 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011838 }
Thierry Fournier3c539322020-11-28 16:05:05 +010011839
11840 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +010011841 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011842}
11843
Thierry Fournierb8cef172020-11-28 15:37:17 +010011844int hlua_post_init()
11845{
Thierry Fournier59f11be2020-11-29 00:37:41 +010011846 int ret;
11847 int i;
11848 int errors;
11849 char *err = NULL;
11850 struct hlua_function *fcn;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011851 struct hlua_reg_filter *reg_flt;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011852
Willy Tarreaub1310492021-08-30 09:35:18 +020011853#if defined(USE_OPENSSL)
Thierry Fournierb8cef172020-11-28 15:37:17 +010011854 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010011855 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010011856 int saved_used_backed = global.ssl_used_backend;
11857 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010011858 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +010011859 global.ssl_used_backend = saved_used_backed;
11860 }
11861#endif
11862
Thierry Fournierc7492592020-11-28 23:57:24 +010011863 /* Perform post init of common thread */
11864 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011865 ha_set_thread(&ha_thread_info[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011866 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
11867 if (ret == 0)
11868 return 0;
11869
11870 /* init remaining lua states and load files */
11871 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
11872
11873 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011874 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011875
11876 /* Init lua state */
11877 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
11878
11879 /* Load lua files */
11880 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
11881 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
11882 if (ret != 0) {
11883 ha_alert("Lua init: %s\n", err);
11884 return 0;
11885 }
11886 }
11887 }
11888
11889 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011890 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011891
11892 /* Execute post init for all states */
11893 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
11894
11895 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011896 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011897
11898 /* run post init */
11899 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
11900 if (ret == 0)
11901 return 0;
11902 }
11903
11904 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011905 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011906
11907 /* control functions registering. Each function must have:
11908 * - only the function_ref[0] set positive and all other to -1
11909 * - only the function_ref[0] set to -1 and all other positive
11910 * This ensure a same reference is not used both in shared
11911 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050011912 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +010011913 * complicated to found for the end user.
11914 */
11915 errors = 0;
11916 list_for_each_entry(fcn, &referenced_functions, l) {
11917 ret = 0;
11918 for (i = 1; i < global.nbthread + 1; i++) {
11919 if (fcn->function_ref[i] == -1)
11920 ret--;
11921 else
11922 ret++;
11923 }
11924 if (abs(ret) != global.nbthread) {
11925 ha_alert("Lua function '%s' is not referenced in all thread. "
11926 "Expect function in all thread or in none thread.\n", fcn->name);
11927 errors++;
11928 continue;
11929 }
11930
11931 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050011932 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
11933 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +010011934 "exclusive.\n", fcn->name);
11935 errors++;
11936 }
11937 }
11938
Christopher Faulet69c581a2021-05-31 08:54:04 +020011939 /* Do the same with registered filters */
11940 list_for_each_entry(reg_flt, &referenced_filters, l) {
11941 ret = 0;
11942 for (i = 1; i < global.nbthread + 1; i++) {
11943 if (reg_flt->flt_ref[i] == -1)
11944 ret--;
11945 else
11946 ret++;
11947 }
11948 if (abs(ret) != global.nbthread) {
11949 ha_alert("Lua filter '%s' is not referenced in all thread. "
11950 "Expect function in all thread or in none thread.\n", reg_flt->name);
11951 errors++;
11952 continue;
11953 }
11954
11955 if ((reg_flt->flt_ref[0] == -1) == (ret < 0)) {
11956 ha_alert("Lua filter '%s' is referenced both ins shared Lua context (through lua-load) "
11957 "and per-thread Lua context (through lua-load-per-thread). these two context "
11958 "exclusive.\n", fcn->name);
11959 errors++;
11960 }
11961 }
11962
11963
Thierry Fournier59f11be2020-11-29 00:37:41 +010011964 if (errors > 0)
11965 return 0;
11966
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050011967 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +010011968 * -1 in order to have probably a segfault if someone use it
11969 */
11970 hlua_state_id = -1;
11971
11972 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +010011973}
11974
Willy Tarreau32f61e22015-03-18 17:54:59 +010011975/* The memory allocator used by the Lua stack. <ud> is a pointer to the
11976 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
11977 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010011978 * allocation. <nsize> is the requested new size. A new allocation is
11979 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +010011980 * zero. This one verifies that the limits are respected but is optimized
11981 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreaua5efdff2021-10-22 16:00:02 +020011982 *
11983 * Warning: while this API ressembles glibc's realloc() a lot, glibc surpasses
11984 * POSIX by making realloc(ptr,0) an effective free(), but others do not do
11985 * that and will simply allocate zero as if it were the result of malloc(0),
11986 * so mapping this onto realloc() will lead to memory leaks on non-glibc
11987 * systems.
Willy Tarreau32f61e22015-03-18 17:54:59 +010011988 */
11989static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
11990{
11991 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +010011992 size_t limit, old, new;
11993
11994 /* a limit of ~0 means unlimited and boot complete, so there's no need
11995 * for accounting anymore.
11996 */
Willy Tarreaua5efdff2021-10-22 16:00:02 +020011997 if (likely(~zone->limit == 0)) {
11998 if (!nsize)
11999 ha_free(&ptr);
12000 else
12001 ptr = realloc(ptr, nsize);
12002 return ptr;
12003 }
Willy Tarreau32f61e22015-03-18 17:54:59 +010012004
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010012005 if (!ptr)
12006 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +010012007
Willy Tarreaucdb53462020-12-02 12:12:00 +010012008 /* enforce strict limits across all threads */
12009 limit = zone->limit;
12010 old = _HA_ATOMIC_LOAD(&zone->allocated);
12011 do {
12012 new = old + nsize - osize;
12013 if (unlikely(nsize && limit && new > limit))
12014 return NULL;
12015 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +010012016
Willy Tarreaua5efdff2021-10-22 16:00:02 +020012017 if (!nsize)
12018 ha_free(&ptr);
12019 else
12020 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +010012021
12022 if (unlikely(!ptr && nsize)) // failed
12023 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
12024
12025 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +010012026 return ptr;
12027}
12028
Thierry Fournierecb83c22020-11-28 15:49:44 +010012029/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012030 * We are in the initialisation process of HAProxy, this abort() is
12031 * tolerated.
12032 */
Thierry Fournierecb83c22020-11-28 15:49:44 +010012033lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010012034{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012035 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012036 int idx;
12037 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012038 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012039 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +010012040 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012041 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012042 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012043 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012044
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012045 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012046 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012047
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012048 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012049 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012050 *context = NULL;
12051
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012052 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012053 * the Lua function can fail with an abort. We are in the initialisation
12054 * process of HAProxy, this abort() is tolerated.
12055 */
12056
Thierry Fournier3c539322020-11-28 16:05:05 +010012057 /* Call post initialisation function in safe environment. */
12058 if (setjmp(safe_ljmp_env) != 0) {
12059 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012060 if (lua_type(L, -1) == LUA_TSTRING)
12061 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010012062 else
12063 error_msg = "critical error";
12064 fprintf(stderr, "Lua init: %s.\n", error_msg);
12065 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010012066 } else {
12067 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010012068 }
12069
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012070 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012071 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012072#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
12073#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
12074#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012075 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012076#endif
12077#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012078 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012079#endif
12080#undef HLUA_PREPEND_PATH_TOSTRING
12081#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012082
Thierry Fournier59f11be2020-11-29 00:37:41 +010012083 /* Apply configured prepend path */
12084 list_for_each_entry(pp, &prepend_path_list, l)
12085 hlua_prepend_path(L, pp->type, pp->path);
12086
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012087 /*
12088 *
12089 * Create "core" object.
12090 *
12091 */
12092
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +010012093 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012094 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012095
Thierry Fournierecb83c22020-11-28 15:49:44 +010012096 /* set the thread id */
12097 hlua_class_const_int(L, "thread", thread_num);
12098
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012099 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +010012100 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012101 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012102
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012103 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012104 hlua_class_function(L, "register_init", hlua_register_init);
12105 hlua_class_function(L, "register_task", hlua_register_task);
12106 hlua_class_function(L, "register_fetches", hlua_register_fetches);
12107 hlua_class_function(L, "register_converters", hlua_register_converters);
12108 hlua_class_function(L, "register_action", hlua_register_action);
12109 hlua_class_function(L, "register_service", hlua_register_service);
12110 hlua_class_function(L, "register_cli", hlua_register_cli);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012111 hlua_class_function(L, "register_filter", hlua_register_filter);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012112 hlua_class_function(L, "yield", hlua_yield);
12113 hlua_class_function(L, "set_nice", hlua_set_nice);
12114 hlua_class_function(L, "sleep", hlua_sleep);
12115 hlua_class_function(L, "msleep", hlua_msleep);
12116 hlua_class_function(L, "add_acl", hlua_add_acl);
12117 hlua_class_function(L, "del_acl", hlua_del_acl);
12118 hlua_class_function(L, "set_map", hlua_set_map);
12119 hlua_class_function(L, "del_map", hlua_del_map);
12120 hlua_class_function(L, "tcp", hlua_socket_new);
William Lallemand3956c4e2021-09-21 16:25:15 +020012121 hlua_class_function(L, "httpclient", hlua_httpclient_new);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012122 hlua_class_function(L, "log", hlua_log);
12123 hlua_class_function(L, "Debug", hlua_log_debug);
12124 hlua_class_function(L, "Info", hlua_log_info);
12125 hlua_class_function(L, "Warning", hlua_log_warning);
12126 hlua_class_function(L, "Alert", hlua_log_alert);
12127 hlua_class_function(L, "done", hlua_done);
12128 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012129
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012130 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012131
12132 /*
12133 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012134 * Create "act" object.
12135 *
12136 */
12137
12138 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012139 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012140
12141 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012142 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
12143 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
12144 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
12145 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
12146 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
12147 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
12148 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
12149 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012150
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012151 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010012152
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012153 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012154
12155 /*
12156 *
Christopher Faulet69c581a2021-05-31 08:54:04 +020012157 * Create "Filter" object.
12158 *
12159 */
12160
12161 /* This table entry is the object "filter" base. */
12162 lua_newtable(L);
12163
12164 /* push flags and constants */
12165 hlua_class_const_int(L, "CONTINUE", 1);
12166 hlua_class_const_int(L, "WAIT", 0);
12167 hlua_class_const_int(L, "ERROR", -1);
12168
12169 hlua_class_const_int(L, "FLT_CFG_FL_HTX", FLT_CFG_FL_HTX);
12170
Christopher Fauletc404f112020-02-26 15:03:09 +010012171 hlua_class_function(L, "wake_time", hlua_set_wake_time);
12172 hlua_class_function(L, "register_data_filter", hlua_register_data_filter);
12173 hlua_class_function(L, "unregister_data_filter", hlua_unregister_data_filter);
12174
Christopher Faulet69c581a2021-05-31 08:54:04 +020012175 lua_setglobal(L, "filter");
12176
12177 /*
12178 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012179 * Register class Map
12180 *
12181 */
12182
12183 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012184 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012185
12186 /* register pattern types. */
12187 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012188 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010012189 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012190 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012191 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010012192 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012193
12194 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012195 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012196
12197 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012198 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012199
Ilya Shipitsind4259502020-04-08 01:07:56 +050012200 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012201 lua_pushstring(L, "__index");
12202 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012203
12204 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012205 hlua_class_function(L, "lookup", hlua_map_lookup);
12206 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012207
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012208 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012209
Thierry Fournier45e78d72016-02-19 18:34:46 +010012210 /* Register previous table in the registry with reference and named entry.
12211 * The function hlua_register_metatable() pops the stack, so we
12212 * previously create a copy of the table.
12213 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012214 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
12215 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012216
12217 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012218 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012219
12220 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012221 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012222
12223 /*
12224 *
William Lallemand30fcca12022-03-30 12:03:12 +020012225 * Register "CertCache" class
12226 *
12227 */
12228
12229 /* Create and fill the metatable. */
12230 lua_newtable(L);
12231 /* Register */
12232 hlua_class_function(L, "set", hlua_ckch_set);
12233 lua_setglobal(L, CLASS_CERTCACHE); /* Create global object called Regex */
12234
12235 /*
12236 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012237 * Register class Channel
12238 *
12239 */
12240
12241 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012242 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012243
Ilya Shipitsind4259502020-04-08 01:07:56 +050012244 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012245 lua_pushstring(L, "__index");
12246 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012247
12248 /* Register . */
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012249 hlua_class_function(L, "data", hlua_channel_get_data);
12250 hlua_class_function(L, "line", hlua_channel_get_line);
12251 hlua_class_function(L, "set", hlua_channel_set_data);
12252 hlua_class_function(L, "remove", hlua_channel_del_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012253 hlua_class_function(L, "append", hlua_channel_append);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012254 hlua_class_function(L, "prepend", hlua_channel_prepend);
12255 hlua_class_function(L, "insert", hlua_channel_insert_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012256 hlua_class_function(L, "send", hlua_channel_send);
12257 hlua_class_function(L, "forward", hlua_channel_forward);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012258 hlua_class_function(L, "input", hlua_channel_get_in_len);
12259 hlua_class_function(L, "output", hlua_channel_get_out_len);
12260 hlua_class_function(L, "may_recv", hlua_channel_may_recv);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012261 hlua_class_function(L, "is_full", hlua_channel_is_full);
12262 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012263
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012264 /* Deprecated API */
12265 hlua_class_function(L, "get", hlua_channel_get);
12266 hlua_class_function(L, "dup", hlua_channel_dup);
12267 hlua_class_function(L, "getline", hlua_channel_getline);
12268 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
12269 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
12270
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012271 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012272
12273 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012274 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012275
12276 /*
12277 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012278 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012279 *
12280 */
12281
12282 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012283 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012284
Ilya Shipitsind4259502020-04-08 01:07:56 +050012285 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012286 lua_pushstring(L, "__index");
12287 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012288
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012289 /* Browse existing fetches and create the associated
12290 * object method.
12291 */
12292 sf = NULL;
12293 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012294 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
12295 * by an underscore.
12296 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020012297 strlcpy2(trash.area, sf->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012298 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012299 if (*p == '.' || *p == '-' || *p == '+')
12300 *p = '_';
12301
12302 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012303 lua_pushstring(L, trash.area);
12304 lua_pushlightuserdata(L, sf);
12305 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
12306 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012307 }
12308
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012309 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012310
12311 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012312 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012313
12314 /*
12315 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012316 * Register class Converters
12317 *
12318 */
12319
12320 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012321 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012322
12323 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012324 lua_pushstring(L, "__index");
12325 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012326
12327 /* Browse existing converters and create the associated
12328 * object method.
12329 */
12330 sc = NULL;
12331 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012332 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
12333 * by an underscore.
12334 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020012335 strlcpy2(trash.area, sc->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012336 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012337 if (*p == '.' || *p == '-' || *p == '+')
12338 *p = '_';
12339
12340 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012341 lua_pushstring(L, trash.area);
12342 lua_pushlightuserdata(L, sc);
12343 lua_pushcclosure(L, hlua_run_sample_conv, 1);
12344 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012345 }
12346
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012347 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012348
12349 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012350 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012351
12352 /*
12353 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012354 * Register class HTTP
12355 *
12356 */
12357
12358 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012359 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012360
Ilya Shipitsind4259502020-04-08 01:07:56 +050012361 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012362 lua_pushstring(L, "__index");
12363 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012364
12365 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012366 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
12367 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
12368 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
12369 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
12370 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
12371 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
12372 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
12373 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
12374 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
12375 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012376
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012377 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
12378 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
12379 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
12380 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
12381 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
12382 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
12383 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012384
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012385 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012386
12387 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012388 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012389
Christopher Fauletdf97ac42020-02-26 16:57:19 +010012390 /*
12391 *
12392 * Register class HTTPMessage
12393 *
12394 */
12395
12396 /* Create and fill the metatable. */
12397 lua_newtable(L);
12398
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050012399 /* Create and fill the __index entry. */
Christopher Fauletdf97ac42020-02-26 16:57:19 +010012400 lua_pushstring(L, "__index");
12401 lua_newtable(L);
12402
12403 /* Register Lua functions. */
12404 hlua_class_function(L, "is_resp", hlua_http_msg_is_resp);
12405 hlua_class_function(L, "get_stline", hlua_http_msg_get_stline);
12406 hlua_class_function(L, "get_headers", hlua_http_msg_get_headers);
12407 hlua_class_function(L, "del_header", hlua_http_msg_del_hdr);
12408 hlua_class_function(L, "rep_header", hlua_http_msg_rep_hdr);
12409 hlua_class_function(L, "rep_value", hlua_http_msg_rep_val);
12410 hlua_class_function(L, "add_header", hlua_http_msg_add_hdr);
12411 hlua_class_function(L, "set_header", hlua_http_msg_set_hdr);
12412 hlua_class_function(L, "set_method", hlua_http_msg_set_meth);
12413 hlua_class_function(L, "set_path", hlua_http_msg_set_path);
12414 hlua_class_function(L, "set_query", hlua_http_msg_set_query);
12415 hlua_class_function(L, "set_uri", hlua_http_msg_set_uri);
12416 hlua_class_function(L, "set_status", hlua_http_msg_set_status);
12417 hlua_class_function(L, "is_full", hlua_http_msg_is_full);
12418 hlua_class_function(L, "may_recv", hlua_http_msg_may_recv);
12419 hlua_class_function(L, "eom", hlua_http_msg_is_eom);
12420 hlua_class_function(L, "input", hlua_http_msg_get_in_len);
12421 hlua_class_function(L, "output", hlua_http_msg_get_out_len);
12422
12423 hlua_class_function(L, "body", hlua_http_msg_get_body);
12424 hlua_class_function(L, "set", hlua_http_msg_set_data);
12425 hlua_class_function(L, "remove", hlua_http_msg_del_data);
12426 hlua_class_function(L, "append", hlua_http_msg_append);
12427 hlua_class_function(L, "prepend", hlua_http_msg_prepend);
12428 hlua_class_function(L, "insert", hlua_http_msg_insert_data);
12429 hlua_class_function(L, "set_eom", hlua_http_msg_set_eom);
12430 hlua_class_function(L, "unset_eom", hlua_http_msg_unset_eom);
12431
12432 hlua_class_function(L, "send", hlua_http_msg_send);
12433 hlua_class_function(L, "forward", hlua_http_msg_forward);
12434
12435 lua_rawset(L, -3);
12436
12437 /* Register previous table in the registry with reference and named entry. */
12438 class_http_msg_ref = hlua_register_metatable(L, CLASS_HTTP_MSG);
William Lallemand3956c4e2021-09-21 16:25:15 +020012439
12440 /*
12441 *
12442 * Register class HTTPClient
12443 *
12444 */
12445
12446 /* Create and fill the metatable. */
12447 lua_newtable(L);
12448 lua_pushstring(L, "__index");
12449 lua_newtable(L);
12450 hlua_class_function(L, "get", hlua_httpclient_get);
William Lallemanddc2cc902021-10-26 11:43:26 +020012451 hlua_class_function(L, "head", hlua_httpclient_head);
12452 hlua_class_function(L, "put", hlua_httpclient_put);
12453 hlua_class_function(L, "post", hlua_httpclient_post);
12454 hlua_class_function(L, "delete", hlua_httpclient_delete);
William Lallemand3956c4e2021-09-21 16:25:15 +020012455 lua_settable(L, -3); /* Sets the __index entry. */
William Lallemandf77f1de2021-09-28 19:10:38 +020012456 /* Register the garbage collector entry. */
12457 lua_pushstring(L, "__gc");
12458 lua_pushcclosure(L, hlua_httpclient_gc, 0);
12459 lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
12460
William Lallemand3956c4e2021-09-21 16:25:15 +020012461
12462
12463 class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012464 /*
12465 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012466 * Register class AppletTCP
12467 *
12468 */
12469
12470 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012471 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012472
Ilya Shipitsind4259502020-04-08 01:07:56 +050012473 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012474 lua_pushstring(L, "__index");
12475 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012476
12477 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012478 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
12479 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
12480 hlua_class_function(L, "send", hlua_applet_tcp_send);
12481 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
12482 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
12483 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
12484 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
12485 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012486
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012487 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012488
12489 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012490 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012491
12492 /*
12493 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012494 * Register class AppletHTTP
12495 *
12496 */
12497
12498 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012499 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012500
Ilya Shipitsind4259502020-04-08 01:07:56 +050012501 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012502 lua_pushstring(L, "__index");
12503 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012504
12505 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012506 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
12507 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
12508 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
12509 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
12510 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
12511 hlua_class_function(L, "getline", hlua_applet_http_getline);
12512 hlua_class_function(L, "receive", hlua_applet_http_recv);
12513 hlua_class_function(L, "send", hlua_applet_http_send);
12514 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
12515 hlua_class_function(L, "set_status", hlua_applet_http_status);
12516 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012517
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012518 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012519
12520 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012521 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012522
12523 /*
12524 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012525 * Register class TXN
12526 *
12527 */
12528
12529 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012530 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012531
Ilya Shipitsind4259502020-04-08 01:07:56 +050012532 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012533 lua_pushstring(L, "__index");
12534 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012535
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010012536 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012537 hlua_class_function(L, "set_priv", hlua_set_priv);
12538 hlua_class_function(L, "get_priv", hlua_get_priv);
12539 hlua_class_function(L, "set_var", hlua_set_var);
12540 hlua_class_function(L, "unset_var", hlua_unset_var);
12541 hlua_class_function(L, "get_var", hlua_get_var);
12542 hlua_class_function(L, "done", hlua_txn_done);
12543 hlua_class_function(L, "reply", hlua_txn_reply_new);
12544 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
12545 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
12546 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
12547 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
12548 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
12549 hlua_class_function(L, "deflog", hlua_txn_deflog);
12550 hlua_class_function(L, "log", hlua_txn_log);
12551 hlua_class_function(L, "Debug", hlua_txn_log_debug);
12552 hlua_class_function(L, "Info", hlua_txn_log_info);
12553 hlua_class_function(L, "Warning", hlua_txn_log_warning);
12554 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010012555
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012556 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012557
12558 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012559 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012560
12561 /*
12562 *
Christopher Faulet700d9e82020-01-31 12:21:52 +010012563 * Register class reply
12564 *
12565 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012566 lua_newtable(L);
12567 lua_pushstring(L, "__index");
12568 lua_newtable(L);
12569 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
12570 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
12571 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
12572 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
12573 lua_settable(L, -3); /* Sets the __index entry. */
12574 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +010012575
12576
12577 /*
12578 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012579 * Register class Socket
12580 *
12581 */
12582
12583 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012584 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012585
Ilya Shipitsind4259502020-04-08 01:07:56 +050012586 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012587 lua_pushstring(L, "__index");
12588 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012589
Baptiste Assmann84bb4932015-03-02 21:40:06 +010012590#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012591 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +010012592#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012593 hlua_class_function(L, "connect", hlua_socket_connect);
12594 hlua_class_function(L, "send", hlua_socket_send);
12595 hlua_class_function(L, "receive", hlua_socket_receive);
12596 hlua_class_function(L, "close", hlua_socket_close);
12597 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
12598 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
12599 hlua_class_function(L, "setoption", hlua_socket_setoption);
12600 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012601
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012602 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012603
12604 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012605 lua_pushstring(L, "__gc");
12606 lua_pushcclosure(L, hlua_socket_gc, 0);
12607 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012608
12609 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012610 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012611
Thierry Fournieraafc7772020-12-04 11:47:47 +010012612 lua_atpanic(L, hlua_panic_safe);
12613
12614 return L;
12615}
12616
12617void hlua_init(void) {
12618 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012619 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +010012620#ifdef USE_OPENSSL
12621 struct srv_kw *kw;
12622 int tmp_error;
12623 char *error;
12624 char *args[] = { /* SSL client configuration. */
12625 "ssl",
12626 "verify",
12627 "none",
12628 NULL
12629 };
12630#endif
12631
12632 /* Init post init function list head */
12633 for (i = 0; i < MAX_THREADS + 1; i++)
12634 LIST_INIT(&hlua_init_functions[i]);
12635
12636 /* Init state for common/shared lua parts */
12637 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012638 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010012639 hlua_states[0] = hlua_init_state(0);
12640
12641 /* Init state 1 for thread 0. We have at least one thread. */
12642 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012643 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010012644 hlua_states[1] = hlua_init_state(1);
12645
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012646 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +020012647 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012648 if (!socket_proxy) {
12649 fprintf(stderr, "Lua init: %s\n", errmsg);
12650 exit(1);
12651 }
12652 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012653
12654 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012655 socket_tcp = new_server(socket_proxy);
12656 if (!socket_tcp) {
12657 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
12658 exit(1);
12659 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012660
12661#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012662 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012663 socket_ssl = new_server(socket_proxy);
12664 if (!socket_ssl) {
12665 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
12666 exit(1);
12667 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012668
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012669 socket_ssl->use_ssl = 1;
12670 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012671
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000012672 for (i = 0; args[i] != NULL; i++) {
12673 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012674 /*
12675 *
12676 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012677 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012678 * features like client certificates and ssl_verify.
12679 *
12680 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012681 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012682 if (tmp_error != 0) {
12683 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
12684 abort(); /* This must be never arrives because the command line
12685 not editable by the user. */
12686 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000012687 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012688 }
12689 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012690#endif
Thierry Fournier75933d42016-01-21 09:30:18 +010012691
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010012692}
Willy Tarreaubb57d942016-12-21 19:04:56 +010012693
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020012694static void hlua_deinit()
12695{
Willy Tarreau186f3762020-12-04 11:48:12 +010012696 int thr;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012697 struct hlua_reg_filter *reg_flt, *reg_flt_bck;
12698
12699 list_for_each_entry_safe(reg_flt, reg_flt_bck, &referenced_filters, l)
12700 release_hlua_reg_filter(reg_flt);
Willy Tarreau186f3762020-12-04 11:48:12 +010012701
12702 for (thr = 0; thr < MAX_THREADS+1; thr++) {
12703 if (hlua_states[thr])
12704 lua_close(hlua_states[thr]);
12705 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +010012706
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020012707 srv_drop(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +010012708
Willy Tarreau0f143af2021-03-05 10:41:48 +010012709#ifdef USE_OPENSSL
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020012710 srv_drop(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +010012711#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012712
12713 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020012714}
12715
12716REGISTER_POST_DEINIT(hlua_deinit);
12717
Willy Tarreau80713382018-11-26 10:19:54 +010012718static void hlua_register_build_options(void)
12719{
Willy Tarreaubb57d942016-12-21 19:04:56 +010012720 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +010012721
Willy Tarreaubb57d942016-12-21 19:04:56 +010012722 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
12723 hap_register_build_opts(ptr, 1);
12724}
Willy Tarreau80713382018-11-26 10:19:54 +010012725
12726INITCALL0(STG_REGISTER, hlua_register_build_options);