blob: 864771aa9643643f2de4c6112bcf203b2ab2f1fc [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);
Christopher Faulet6e1bbc42022-12-12 08:08:15 +01002006 sc_ic(sc)->flags |= CF_READ_EVENT;
Willy Tarreau5321da92022-05-06 11:57:34 +02002007 notification_wake(&ctx->wake_on_read);
2008 notification_wake(&ctx->wake_on_write);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002009 stream_shutdown(__sc_strm(sc), SF_ERR_KILLED);
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002010 }
2011
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002012 /* If we can't write, wakeup the pending write signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002013 if (channel_output_closed(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002014 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002015
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002016 /* If we can't read, wakeup the pending read signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002017 if (channel_input_closed(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002018 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002019
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002020 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002021 * to be notified whenever the connection completes.
2022 */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002023 if (sc_opposite(sc)->state < SC_ST_EST) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02002024 applet_need_more_data(appctx);
Willy Tarreaub23edc82022-05-24 16:49:03 +02002025 se_need_remote_conn(appctx->sedesc);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002026 applet_have_more_data(appctx);
Willy Tarreaud4da1962015-04-20 01:31:23 +02002027 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002028 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002029
2030 /* This function is called after the connect. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002031 ctx->connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002032
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002033 /* Wake the tasks which wants to write if the buffer have available space. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002034 if (channel_may_recv(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002035 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002036
2037 /* Wake the tasks which wants to read if the buffer contains data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002038 if (!channel_is_empty(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002039 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002040
2041 /* Some data were injected in the buffer, notify the stream
2042 * interface.
2043 */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002044 if (!channel_is_empty(sc_ic(sc)))
2045 sc_update(sc);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002046
2047 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01002048 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002049 */
Willy Tarreau5321da92022-05-06 11:57:34 +02002050 if (notification_registered(&ctx->wake_on_write))
Willy Tarreau4164eb92022-05-25 15:42:03 +02002051 applet_have_more_data(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002052}
2053
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002054static int hlua_socket_init(struct appctx *appctx)
2055{
2056 struct hlua_csk_ctx *ctx = appctx->svcctx;
2057 struct stream *s;
2058
2059 if (appctx_finalize_startup(appctx, socket_proxy, &BUF_NULL) == -1)
2060 goto error;
2061
2062 s = appctx_strm(appctx);
2063
Willy Tarreau4596fe22022-05-17 19:07:51 +02002064 /* Configure "right" stream connector. This stconn is used to connect
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002065 * and retrieve data from the server. The connection is initialized
2066 * with the "struct server".
2067 */
Willy Tarreau74568cf2022-05-27 09:03:30 +02002068 sc_set_state(s->scb, SC_ST_ASS);
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002069
2070 /* Force destination server. */
2071 s->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
2072 s->target = &socket_tcp->obj_type;
2073
2074 ctx->appctx = appctx;
2075 return 0;
2076
2077 error:
2078 return -1;
2079}
2080
Willy Tarreau87b09662015-04-03 00:22:06 +02002081/* This function is called when the "struct stream" is destroyed.
2082 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002083 * Wake all the pending signals.
2084 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002085static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002086{
Willy Tarreau5321da92022-05-06 11:57:34 +02002087 struct hlua_csk_ctx *ctx = appctx->svcctx;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002088 struct xref *peer;
2089
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002090 /* Remove my link in the original objects. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002091 peer = xref_get_peer_and_lock(&ctx->xref);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002092 if (peer)
Willy Tarreau5321da92022-05-06 11:57:34 +02002093 xref_disconnect(&ctx->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002094
2095 /* Wake all the task waiting for me. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002096 notification_wake(&ctx->wake_on_read);
2097 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002098}
2099
2100/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02002101 * uses this object. If the stream does not exists, just quit.
2102 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002103 * pending signal can rest in the read and write lists. destroy
2104 * it.
2105 */
2106__LJMP static int hlua_socket_gc(lua_State *L)
2107{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002108 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002109 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002110 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002111
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002112 MAY_LJMP(check_args(L, 1, "__gc"));
2113
2114 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002115 peer = xref_get_peer_and_lock(&socket->xref);
2116 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002117 return 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02002118
2119 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002120
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002121 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002122 ctx->die = 1;
2123 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002124
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002125 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002126 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002127 return 0;
2128}
2129
2130/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02002131 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002132 */
sada05ed3302018-05-11 11:48:18 -07002133__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002134{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002135 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002136 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002137 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002138 struct hlua *hlua;
2139
2140 /* Get hlua struct, or NULL if we execute from main lua state */
2141 hlua = hlua_gethlua(L);
2142 if (!hlua)
2143 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002144
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002145 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002146
2147 /* Check if we run on the same thread than the xreator thread.
2148 * We cannot access to the socket if the thread is different.
2149 */
2150 if (socket->tid != tid)
2151 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2152
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002153 peer = xref_get_peer_and_lock(&socket->xref);
2154 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002155 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01002156
2157 hlua->gc_count--;
Willy Tarreau5321da92022-05-06 11:57:34 +02002158 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002159
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002160 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002161 ctx->die = 1;
2162 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002163
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002164 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002165 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002166 return 0;
2167}
2168
sada05ed3302018-05-11 11:48:18 -07002169/* The close function calls close_helper.
2170 */
2171__LJMP static int hlua_socket_close(lua_State *L)
2172{
2173 MAY_LJMP(check_args(L, 1, "close"));
2174 return hlua_socket_close_helper(L);
2175}
2176
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002177/* This Lua function assumes that the stack contain three parameters.
2178 * 1 - USERDATA containing a struct socket
2179 * 2 - INTEGER with values of the macro defined below
2180 * If the integer is -1, we must read at most one line.
2181 * If the integer is -2, we ust read all the data until the
2182 * end of the stream.
2183 * If the integer is positive value, we must read a number of
2184 * bytes corresponding to this value.
2185 */
2186#define HLSR_READ_LINE (-1)
2187#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002188__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002189{
2190 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
2191 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002192 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002193 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002194 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002195 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002196 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02002197 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002198 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02002199 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002200 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002201 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01002202 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002203 struct stream *s;
2204 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002205 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002206
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002207 /* Get hlua struct, or NULL if we execute from main lua state */
2208 hlua = hlua_gethlua(L);
2209
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002210 /* Check if this lua stack is schedulable. */
2211 if (!hlua || !hlua->task)
2212 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
2213 "'frontend', 'backend' or 'task'"));
2214
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002215 /* Check if we run on the same thread than the xreator thread.
2216 * We cannot access to the socket if the thread is different.
2217 */
2218 if (socket->tid != tid)
2219 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2220
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002221 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002222 peer = xref_get_peer_and_lock(&socket->xref);
2223 if (!peer)
2224 goto no_peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002225
2226 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2227 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002228 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002229
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002230 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002231 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002232 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002233 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002234 if (nblk < 0) /* Connection close. */
2235 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002236 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002237 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002238
2239 /* remove final \r\n. */
2240 if (nblk == 1) {
2241 if (blk1[len1-1] == '\n') {
2242 len1--;
2243 skip_at_end++;
2244 if (blk1[len1-1] == '\r') {
2245 len1--;
2246 skip_at_end++;
2247 }
2248 }
2249 }
2250 else {
2251 if (blk2[len2-1] == '\n') {
2252 len2--;
2253 skip_at_end++;
2254 if (blk2[len2-1] == '\r') {
2255 len2--;
2256 skip_at_end++;
2257 }
2258 }
2259 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002260 }
2261
2262 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002263 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002264 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002265 if (nblk < 0) /* Connection close. */
2266 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002267 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002268 goto connection_empty;
2269 }
2270
2271 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002272 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002273 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002274 if (nblk < 0) /* Connection close. */
2275 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002276 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002277 goto connection_empty;
2278
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002279 missing_bytes = wanted - socket->b.n;
2280 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002281 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002282 len1 = missing_bytes;
2283 } if (nblk == 2 && len1 + len2 > missing_bytes)
2284 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002285 }
2286
2287 len = len1;
2288
2289 luaL_addlstring(&socket->b, blk1, len1);
2290 if (nblk == 2) {
2291 len += len2;
2292 luaL_addlstring(&socket->b, blk2, len2);
2293 }
2294
2295 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002296 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002297
2298 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002299 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002300
2301 /* If the pattern reclaim to read all the data
2302 * in the connection, got out.
2303 */
2304 if (wanted == HLSR_READ_ALL)
2305 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002306 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002307 goto connection_empty;
2308
2309 /* Return result. */
2310 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002311 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002312 return 1;
2313
2314connection_closed:
2315
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002316 xref_unlock(&socket->xref, peer);
2317
2318no_peer:
2319
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002320 /* If the buffer containds data. */
2321 if (socket->b.n > 0) {
2322 luaL_pushresult(&socket->b);
2323 return 1;
2324 }
2325 lua_pushnil(L);
2326 lua_pushstring(L, "connection closed.");
2327 return 2;
2328
2329connection_empty:
2330
Willy Tarreau5321da92022-05-06 11:57:34 +02002331 if (!notification_new(&hlua->com, &csk_ctx->wake_on_read, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002332 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002333 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002334 }
2335 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002336 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002337 return 0;
2338}
2339
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002340/* This Lua function gets two parameters. The first one can be string
2341 * or a number. If the string is "*l", the user requires one line. If
2342 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002343 * If the value is a number, the user require a number of bytes equal
2344 * to the value. The default value is "*l" (a line).
2345 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002346 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002347 * integer takes this values:
2348 * -1 : read a line
2349 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002350 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002351 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002352 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002353 * concatenated with the read data.
2354 */
2355__LJMP static int hlua_socket_receive(struct lua_State *L)
2356{
2357 int wanted = HLSR_READ_LINE;
2358 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002359 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002360 char *error;
2361 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002362 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002363
2364 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2365 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2366
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002367 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002368
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002369 /* Check if we run on the same thread than the xreator thread.
2370 * We cannot access to the socket if the thread is different.
2371 */
2372 if (socket->tid != tid)
2373 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2374
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002375 /* check for pattern. */
2376 if (lua_gettop(L) >= 2) {
2377 type = lua_type(L, 2);
2378 if (type == LUA_TSTRING) {
2379 pattern = lua_tostring(L, 2);
2380 if (strcmp(pattern, "*a") == 0)
2381 wanted = HLSR_READ_ALL;
2382 else if (strcmp(pattern, "*l") == 0)
2383 wanted = HLSR_READ_LINE;
2384 else {
2385 wanted = strtoll(pattern, &error, 10);
2386 if (*error != '\0')
2387 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2388 }
2389 }
2390 else if (type == LUA_TNUMBER) {
2391 wanted = lua_tointeger(L, 2);
2392 if (wanted < 0)
2393 WILL_LJMP(luaL_error(L, "Unsupported size."));
2394 }
2395 }
2396
2397 /* Set pattern. */
2398 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002399
2400 /* Check if we would replace the top by itself. */
2401 if (lua_gettop(L) != 2)
2402 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002403
Christopher Fauletc31b2002021-05-03 10:11:13 +02002404 /* Save index of the top of the stack because since buffers are used, it
2405 * may change
2406 */
2407 lastarg = lua_gettop(L);
2408
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002409 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002410 luaL_buffinit(L, &socket->b);
2411
2412 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002413 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002414 if (lua_type(L, 3) != LUA_TSTRING)
2415 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2416 pattern = lua_tolstring(L, 3, &len);
2417 luaL_addlstring(&socket->b, pattern, len);
2418 }
2419
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002420 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002421}
2422
2423/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002424 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002425 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002426static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002427{
2428 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002429 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002430 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002431 struct appctx *appctx;
2432 size_t buf_len;
2433 const char *buf;
2434 int len;
2435 int send_len;
2436 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002437 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002438 struct stream *s;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002439 struct stconn *sc;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002440
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002441 /* Get hlua struct, or NULL if we execute from main lua state */
2442 hlua = hlua_gethlua(L);
2443
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002444 /* Check if this lua stack is schedulable. */
2445 if (!hlua || !hlua->task)
2446 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2447 "'frontend', 'backend' or 'task'"));
2448
2449 /* Get object */
2450 socket = MAY_LJMP(hlua_checksocket(L, 1));
2451 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002452 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002453
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002454 /* Check if we run on the same thread than the xreator thread.
2455 * We cannot access to the socket if the thread is different.
2456 */
2457 if (socket->tid != tid)
2458 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2459
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002460 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002461 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002462 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002463 lua_pushinteger(L, -1);
2464 return 1;
2465 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002466
2467 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2468 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002469 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002470 s = __sc_strm(sc);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002471
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002472 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002473 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002474 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002475 lua_pushinteger(L, -1);
2476 return 1;
2477 }
2478
2479 /* Update the input buffer data. */
2480 buf += sent;
2481 send_len = buf_len - sent;
2482
2483 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002484 if (sent >= buf_len) {
2485 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002486 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002487 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002488
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002489 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002490 * the request buffer if its not required.
2491 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002492 if (s->req.buf.size == 0) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02002493 if (!sc_alloc_ibuf(sc, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002494 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002495 }
2496
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002497 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002498 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002499 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002500 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002501 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002502
2503 /* send data */
2504 if (len < send_len)
2505 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002506 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002507
2508 /* "Not enough space" (-1), "Buffer too little to contain
2509 * the data" (-2) are not expected because the available length
2510 * is tested.
2511 * Other unknown error are also not expected.
2512 */
2513 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002514 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002515 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002516
sada05ed3302018-05-11 11:48:18 -07002517 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002518 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002519 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002520 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002521 return 1;
2522 }
2523
2524 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002525 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002526
Christopher Fauletf8413cb2023-02-07 16:06:14 +01002527 sc_ep_reset_rex(s->scf);;
2528 sc_ep_reset_wex(s->scb);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002529
2530 /* Update length sent. */
2531 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002532 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002533
2534 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002535 if (sent + len >= buf_len) {
2536 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002537 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002538 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002539
2540hlua_socket_write_yield_return:
Willy Tarreau5321da92022-05-06 11:57:34 +02002541 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002542 xref_unlock(&socket->xref, peer);
2543 WILL_LJMP(luaL_error(L, "out of memory"));
2544 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002545 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002546 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002547 return 0;
2548}
2549
2550/* This function initiate the send of data. It just check the input
2551 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002552 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002553 * "hlua_socket_write_yield" that can yield.
2554 *
2555 * The Lua function gets between 3 and 4 parameters. The first one is
2556 * the associated object. The second is a string buffer. The third is
2557 * a facultative integer that represents where is the buffer position
2558 * of the start of the data that can send. The first byte is the
2559 * position "1". The default value is "1". The fourth argument is a
2560 * facultative integer that represents where is the buffer position
2561 * of the end of the data that can send. The default is the last byte.
2562 */
2563static int hlua_socket_send(struct lua_State *L)
2564{
2565 int i;
2566 int j;
2567 const char *buf;
2568 size_t buf_len;
2569
2570 /* Check number of arguments. */
2571 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2572 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2573
2574 /* Get the string. */
2575 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2576
2577 /* Get and check j. */
2578 if (lua_gettop(L) == 4) {
2579 j = MAY_LJMP(luaL_checkinteger(L, 4));
2580 if (j < 0)
2581 j = buf_len + j + 1;
2582 if (j > buf_len)
2583 j = buf_len + 1;
2584 lua_pop(L, 1);
2585 }
2586 else
2587 j = buf_len;
2588
2589 /* Get and check i. */
2590 if (lua_gettop(L) == 3) {
2591 i = MAY_LJMP(luaL_checkinteger(L, 3));
2592 if (i < 0)
2593 i = buf_len + i + 1;
2594 if (i > buf_len)
2595 i = buf_len + 1;
2596 lua_pop(L, 1);
2597 } else
2598 i = 1;
2599
2600 /* Check bth i and j. */
2601 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002602 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002603 return 1;
2604 }
2605 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002606 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002607 return 1;
2608 }
2609 if (i == 0)
2610 i = 1;
2611 if (j == 0)
2612 j = 1;
2613
2614 /* Pop the string. */
2615 lua_pop(L, 1);
2616
2617 /* Update the buffer length. */
2618 buf += i - 1;
2619 buf_len = j - i + 1;
2620 lua_pushlstring(L, buf, buf_len);
2621
2622 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002623 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002624
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002625 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002626}
2627
Willy Tarreau22b0a682015-06-17 19:43:49 +02002628#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Christopher Faulete6465b32021-10-22 15:36:08 +02002629__LJMP static inline int hlua_socket_info(struct lua_State *L, const struct sockaddr_storage *addr)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002630{
2631 static char buffer[SOCKET_INFO_MAX_LEN];
2632 int ret;
2633 int len;
2634 char *p;
2635
2636 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2637 if (ret <= 0) {
2638 lua_pushnil(L);
2639 return 1;
2640 }
2641
2642 if (ret == AF_UNIX) {
2643 lua_pushstring(L, buffer+1);
2644 return 1;
2645 }
2646 else if (ret == AF_INET6) {
2647 buffer[0] = '[';
2648 len = strlen(buffer);
2649 buffer[len] = ']';
2650 len++;
2651 buffer[len] = ':';
2652 len++;
2653 p = buffer;
2654 }
2655 else if (ret == AF_INET) {
2656 p = buffer + 1;
2657 len = strlen(p);
2658 p[len] = ':';
2659 len++;
2660 }
2661 else {
2662 lua_pushnil(L);
2663 return 1;
2664 }
2665
2666 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2667 lua_pushnil(L);
2668 return 1;
2669 }
2670
2671 lua_pushstring(L, p);
2672 return 1;
2673}
2674
2675/* Returns information about the peer of the connection. */
2676__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2677{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002678 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002679 struct xref *peer;
2680 struct appctx *appctx;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002681 struct stconn *sc;
Christopher Faulet16f16af2021-10-27 09:34:56 +02002682 const struct sockaddr_storage *dst;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002683 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002684
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002685 MAY_LJMP(check_args(L, 1, "getpeername"));
2686
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002687 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002688
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002689 /* Check if we run on the same thread than the xreator thread.
2690 * We cannot access to the socket if the thread is different.
2691 */
2692 if (socket->tid != tid)
2693 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2694
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002695 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002696 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002697 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002698 lua_pushnil(L);
2699 return 1;
2700 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002701
2702 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002703 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002704 dst = sc_dst(sc_opposite(sc));
Christopher Faulet16f16af2021-10-27 09:34:56 +02002705 if (!dst) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002706 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002707 lua_pushnil(L);
2708 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002709 }
2710
Christopher Faulet16f16af2021-10-27 09:34:56 +02002711 ret = MAY_LJMP(hlua_socket_info(L, dst));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002712 xref_unlock(&socket->xref, peer);
2713 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002714}
2715
2716/* Returns information about my connection side. */
2717static int hlua_socket_getsockname(struct lua_State *L)
2718{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002719 struct hlua_socket *socket;
2720 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002721 struct appctx *appctx;
2722 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002723 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002724 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002725
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002726 MAY_LJMP(check_args(L, 1, "getsockname"));
2727
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002728 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002729
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002730 /* Check if we run on the same thread than the xreator thread.
2731 * We cannot access to the socket if the thread is different.
2732 */
2733 if (socket->tid != tid)
2734 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2735
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002736 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002737 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002738 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002739 lua_pushnil(L);
2740 return 1;
2741 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002742
2743 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002744 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002745
Willy Tarreaufd9417b2022-05-18 16:23:22 +02002746 conn = sc_conn(s->scb);
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002747 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002748 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002749 lua_pushnil(L);
2750 return 1;
2751 }
2752
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002753 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002754 xref_unlock(&socket->xref, peer);
2755 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002756}
2757
2758/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002759static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002760 .obj_type = OBJ_TYPE_APPLET,
2761 .name = "<LUA_TCP>",
2762 .fct = hlua_socket_handler,
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002763 .init = hlua_socket_init,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002764 .release = hlua_socket_release,
2765};
2766
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002767__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002768{
2769 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002770 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002771 struct xref *peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002772 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002773 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002774 struct stream *s;
2775
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002776 /* Get hlua struct, or NULL if we execute from main lua state */
2777 hlua = hlua_gethlua(L);
2778 if (!hlua)
2779 return 0;
2780
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002781 /* Check if we run on the same thread than the xreator thread.
2782 * We cannot access to the socket if the thread is different.
2783 */
2784 if (socket->tid != tid)
2785 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2786
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002787 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002788 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002789 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002790 lua_pushnil(L);
2791 lua_pushstring(L, "Can't connect");
2792 return 2;
2793 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002794
2795 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2796 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002797 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002798
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002799 /* Check if we run on the same thread than the xreator thread.
2800 * We cannot access to the socket if the thread is different.
2801 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002802 if (socket->tid != tid) {
2803 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002804 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002805 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002806
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002807 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002808 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002809 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002810 lua_pushnil(L);
2811 lua_pushstring(L, "Can't connect");
2812 return 2;
2813 }
2814
Willy Tarreau8e7c6e62022-05-18 17:58:02 +02002815 appctx = __sc_appctx(s->scf);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002816
2817 /* Check for connection established. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002818 if (csk_ctx->connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002819 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002820 lua_pushinteger(L, 1);
2821 return 1;
2822 }
2823
Willy Tarreau5321da92022-05-06 11:57:34 +02002824 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002825 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002826 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002827 }
2828 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002829 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002830 return 0;
2831}
2832
2833/* This function fail or initite the connection. */
2834__LJMP static int hlua_socket_connect(struct lua_State *L)
2835{
2836 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002837 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002838 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002839 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002840 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002841 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002842 int low, high;
2843 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002844 struct xref *peer;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002845 struct stconn *sc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002846 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002847
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002848 if (lua_gettop(L) < 2)
2849 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002850
2851 /* Get args. */
2852 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002853
2854 /* Check if we run on the same thread than the xreator thread.
2855 * We cannot access to the socket if the thread is different.
2856 */
2857 if (socket->tid != tid)
2858 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2859
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002860 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002861 if (lua_gettop(L) >= 3) {
2862 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002863 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002864
Tim Duesterhus6edab862018-01-06 19:04:45 +01002865 /* Force the ip to end with a colon, to support IPv6 addresses
2866 * that are not enclosed within square brackets.
2867 */
2868 if (port > 0) {
2869 luaL_buffinit(L, &b);
2870 luaL_addstring(&b, ip);
2871 luaL_addchar(&b, ':');
2872 luaL_pushresult(&b);
2873 ip = lua_tolstring(L, lua_gettop(L), NULL);
2874 }
2875 }
2876
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002877 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002878 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002879 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002880 lua_pushnil(L);
2881 return 1;
2882 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002883
2884 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002885 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 +02002886 if (!addr) {
2887 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002888 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002889 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002890
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002891 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002892 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002893 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002894 if (port == -1) {
2895 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002896 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002897 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002898 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2899 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002900 if (port == -1) {
2901 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002902 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002903 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002904 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002905 }
2906 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002907
Willy Tarreau5321da92022-05-06 11:57:34 +02002908 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2909 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002910 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002911 s = __sc_strm(sc);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002912
Willy Tarreau3e7be362022-05-27 10:35:27 +02002913 if (!sockaddr_alloc(&sc_opposite(sc)->dst, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002914 xref_unlock(&socket->xref, peer);
2915 WILL_LJMP(luaL_error(L, "connect: internal error"));
2916 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002917
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002918 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002919 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002920 if (!hlua)
2921 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002922
2923 /* inform the stream that we want to be notified whenever the
2924 * connection completes.
2925 */
Willy Tarreau90e8b452022-05-25 18:21:43 +02002926 applet_need_more_data(appctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002927 applet_have_more_data(appctx);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002928 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002929
Willy Tarreauf31af932020-01-14 09:59:38 +01002930 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002931
Willy Tarreau5321da92022-05-06 11:57:34 +02002932 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002933 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002934 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002935 }
2936 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002937
2938 task_wakeup(s->task, TASK_WOKEN_INIT);
2939 /* Return yield waiting for connection. */
2940
Willy Tarreau9635e032018-10-16 17:52:55 +02002941 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002942
2943 return 0;
2944}
2945
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002946#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002947__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
2948{
2949 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002950 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002951 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002952
2953 MAY_LJMP(check_args(L, 3, "connect_ssl"));
2954 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002955
2956 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002957 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002958 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002959 lua_pushnil(L);
2960 return 1;
2961 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002962
Willy Tarreau0698c802022-05-11 14:09:57 +02002963 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002964
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002965 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002966 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002967 return MAY_LJMP(hlua_socket_connect(L));
2968}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002969#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002970
2971__LJMP static int hlua_socket_setoption(struct lua_State *L)
2972{
2973 return 0;
2974}
2975
2976__LJMP static int hlua_socket_settimeout(struct lua_State *L)
2977{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002978 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002979 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02002980 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002981 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002982 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002983
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002984 MAY_LJMP(check_args(L, 2, "settimeout"));
2985
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002986 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02002987
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002988 /* convert the timeout to millis */
2989 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002990
Thierry Fournier17a921b2018-03-08 09:59:02 +01002991 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02002992 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01002993 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
2994
Mark Lakes56cc1252018-03-27 09:48:06 +02002995 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002996 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02002997
2998 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002999 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003000 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02003001
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003002 /* Check if we run on the same thread than the xreator thread.
3003 * We cannot access to the socket if the thread is different.
3004 */
3005 if (socket->tid != tid)
3006 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
3007
Mark Lakes56cc1252018-03-27 09:48:06 +02003008 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003009 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003010 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003011 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
3012 WILL_LJMP(lua_error(L));
3013 return 0;
3014 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003015
Willy Tarreau0698c802022-05-11 14:09:57 +02003016 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003017
Cyril Bonté7bb63452018-08-17 23:51:02 +02003018 s->sess->fe->timeout.connect = tmout;
Christopher Fauleted7e66f2023-02-07 11:09:15 +01003019 s->scf->rto = s->scf->wto = tmout;
3020 s->scb->rto = s->scb->wto = tmout;
Christopher Fauletf8413cb2023-02-07 16:06:14 +01003021 sc_ep_set_rex(s->scf, tmout);
3022 sc_ep_set_wex(s->scf, tmout);
3023 sc_ep_set_rex(s->scb, tmout);
3024 sc_ep_set_wex(s->scb, tmout);
Cyril Bonté7bb63452018-08-17 23:51:02 +02003025
3026 s->task->expire = tick_add_ifset(now_ms, tmout);
3027 task_queue(s->task);
3028
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003029 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003030
Thierry Fourniere9636f12018-03-08 09:54:32 +01003031 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01003032 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003033}
3034
3035__LJMP static int hlua_socket_new(lua_State *L)
3036{
3037 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02003038 struct hlua_csk_ctx *ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003039 struct appctx *appctx;
3040
3041 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003042 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003043 hlua_pusherror(L, "socket: full stack");
3044 goto out_fail_conf;
3045 }
3046
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003047 /* Create the object: obj[0] = userdata. */
3048 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003049 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003050 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003051 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003052 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003053
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003054 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01003055 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01003056 hlua_pusherror(L, "socket: uninitialized pools.");
3057 goto out_fail_conf;
3058 }
3059
Willy Tarreau87b09662015-04-03 00:22:06 +02003060 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003061 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
3062 lua_setmetatable(L, -2);
3063
Willy Tarreaud420a972015-04-06 00:39:18 +02003064 /* Create the applet context */
Christopher Faulet6095d572022-05-16 17:09:48 +02003065 appctx = appctx_new_here(&update_applet, NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003066 if (!appctx) {
3067 hlua_pusherror(L, "socket: out of memory");
Christopher Fauleta9e8b392022-03-23 11:01:09 +01003068 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003069 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003070 ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
3071 ctx->connected = 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02003072 ctx->die = 0;
3073 LIST_INIT(&ctx->wake_on_write);
3074 LIST_INIT(&ctx->wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02003075
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003076 if (appctx_init(appctx) == -1) {
3077 hlua_pusherror(L, "socket: fail to init applet.");
Christopher Faulet13a35e52021-12-20 15:34:16 +01003078 goto out_fail_appctx;
3079 }
3080
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003081 /* Initialise cross reference between stream and Lua socket object. */
Willy Tarreau5321da92022-05-06 11:57:34 +02003082 xref_create(&socket->xref, &ctx->xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003083 return 1;
3084
Christopher Faulet13a35e52021-12-20 15:34:16 +01003085 out_fail_appctx:
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003086 appctx_free_on_early_error(appctx);
Willy Tarreaud420a972015-04-06 00:39:18 +02003087 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003088 WILL_LJMP(lua_error(L));
3089 return 0;
3090}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01003091
3092/*
3093 *
3094 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003095 * Class Channel
3096 *
3097 *
3098 */
3099
3100/* Returns the struct hlua_channel join to the class channel in the
3101 * stack entry "ud" or throws an argument error.
3102 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003103__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003104{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003105 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003106}
3107
Willy Tarreau47860ed2015-03-10 14:07:50 +01003108/* Pushes the channel onto the top of the stack. If the stask does not have a
3109 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003110 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01003111static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003112{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003113 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003114 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003115 return 0;
3116
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003117 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003118 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003119 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003120
3121 /* Pop a class sesison metatable and affect it to the userdata. */
3122 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
3123 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003124 return 1;
3125}
3126
Christopher Faulet9f55a502020-02-25 15:21:02 +01003127/* Helper function returning a filter attached to a channel at the position <ud>
3128 * in the stack, filling the current offset and length of the filter. If no
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05003129 * filter is attached, NULL is returned and <offset> and <len> are not
Christopher Faulet9f55a502020-02-25 15:21:02 +01003130 * initialized.
3131 */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003132static 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 +01003133{
3134 struct filter *filter = NULL;
3135
3136 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
3137 struct hlua_flt_ctx *flt_ctx;
3138
3139 filter = lua_touserdata (L, -1);
3140 flt_ctx = filter->ctx;
3141 if (hlua_filter_from_payload(filter)) {
3142 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
3143 *len = flt_ctx->cur_len[CHN_IDX(chn)];
3144 }
3145 }
3146
3147 lua_pop(L, 1);
3148 return filter;
3149}
3150
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003151/* Copies <len> bytes of data present in the channel's buffer, starting at the
3152* offset <offset>, and put it in a LUA string variable. It is the caller
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003153* responsibility to ensure <len> and <offset> are valid. It always return the
3154* length of the built string. <len> may be 0, in this case, an empty string is
3155* created and 0 is returned.
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003156*/
3157static inline int _hlua_channel_dup(struct channel *chn, lua_State *L, size_t offset, size_t len)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003158{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003159 size_t block1, block2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003160 luaL_Buffer b;
3161
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003162 block1 = len;
3163 if (block1 > b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset)))
3164 block1 = b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset));
3165 block2 = len - block1;
3166
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003167 luaL_buffinit(L, &b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003168 luaL_addlstring(&b, b_peek(&chn->buf, offset), block1);
3169 if (block2)
3170 luaL_addlstring(&b, b_orig(&chn->buf), block2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003171 luaL_pushresult(&b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003172 return len;
3173}
3174
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003175/* Inserts the string <str> to the channel's buffer at the offset <offset>. This
3176 * function returns -1 if data cannot be copied. Otherwise, it returns the
3177 * number of bytes copied.
3178 */
3179static int _hlua_channel_insert(struct channel *chn, lua_State *L, struct ist str, size_t offset)
3180{
3181 int ret = 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003182
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003183 /* Nothing to do, just return */
3184 if (unlikely(istlen(str) == 0))
3185 goto end;
3186
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003187 if (istlen(str) > c_room(chn)) {
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003188 ret = -1;
3189 goto end;
3190 }
3191 ret = b_insert_blk(&chn->buf, offset, istptr(str), istlen(str));
3192
3193 end:
3194 return ret;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003195}
3196
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003197/* Removes <len> bytes of data at the absolute position <offset>.
3198 */
3199static void _hlua_channel_delete(struct channel *chn, size_t offset, size_t len)
3200{
3201 size_t end = offset + len;
3202
3203 if (b_peek(&chn->buf, end) != b_tail(&chn->buf))
3204 b_move(&chn->buf, b_peek_ofs(&chn->buf, end),
3205 b_data(&chn->buf) - end, -len);
3206 b_sub(&chn->buf, len);
3207}
3208
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003209/* Copies input data in the channel's buffer. It is possible to set a specific
3210 * offset (0 by default) and a length (all remaining input data starting for the
3211 * offset by default). If there is not enough input data and more data can be
3212 * received, this function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003213 *
3214 * From an action, All input data are considered. For a filter, the offset and
3215 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003216 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003217__LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003218{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003219 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003220 struct filter *filter;
3221 size_t input, output;
3222 int offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003223
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003224 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003225
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003226 output = co_data(chn);
3227 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003228
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003229 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3230 if (filter && !hlua_filter_from_payload(filter))
3231 WILL_LJMP(lua_error(L));
3232
3233 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003234 if (lua_gettop(L) > 1) {
3235 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3236 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003237 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003238 offset += output;
3239 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003240 lua_pushfstring(L, "offset out of range.");
3241 WILL_LJMP(lua_error(L));
3242 }
3243 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003244 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003245 if (lua_gettop(L) == 3) {
3246 len = MAY_LJMP(luaL_checkinteger(L, 3));
3247 if (!len)
3248 goto dup;
3249 if (len == -1)
3250 len = global.tune.bufsize;
3251 if (len < 0) {
3252 lua_pushfstring(L, "length out of range.");
3253 WILL_LJMP(lua_error(L));
3254 }
3255 }
3256
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003257 /* Wait for more data if possible if no length was specified and there
3258 * is no data or not enough data was received.
3259 */
3260 if (!len || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003261 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3262 /* Yield waiting for more data, as requested */
3263 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_data_yield, TICK_ETERNITY, 0));
3264 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003265
3266 /* Return 'nil' if there is no data and the channel can't receive more data */
3267 if (!len) {
3268 lua_pushnil(L);
3269 return -1;
3270 }
3271
3272 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003273 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003274 }
3275
3276 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003277 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003278 return 1;
3279}
3280
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003281/* Copies the first line (including the trailing LF) of input data in the
3282 * channel's buffer. It is possible to set a specific offset (0 by default) and
3283 * a length (all remaining input data starting for the offset by default). If
3284 * there is not enough input data and more data can be received, the function
3285 * yields. If a length is explicitly specified, no more data are
3286 * copied. Otherwise, if no LF is found and more data can be received, this
3287 * function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003288 *
3289 * From an action, All input data are considered. For a filter, the offset and
3290 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003291 */
3292__LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003293{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003294 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003295 struct filter *filter;
3296 size_t l, input, output;
3297 int offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003298
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003299 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003300 output = co_data(chn);
3301 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003302
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003303 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3304 if (filter && !hlua_filter_from_payload(filter))
3305 WILL_LJMP(lua_error(L));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003306
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003307 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003308 if (lua_gettop(L) > 1) {
3309 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3310 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003311 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003312 offset += output;
3313 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003314 lua_pushfstring(L, "offset out of range.");
3315 WILL_LJMP(lua_error(L));
3316 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003317 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003318
3319 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003320 if (lua_gettop(L) == 3) {
3321 len = MAY_LJMP(luaL_checkinteger(L, 3));
3322 if (!len)
3323 goto dup;
3324 if (len == -1)
3325 len = global.tune.bufsize;
3326 if (len < 0) {
3327 lua_pushfstring(L, "length out of range.");
3328 WILL_LJMP(lua_error(L));
3329 }
3330 }
3331
3332 for (l = 0; l < len; l++) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003333 if (l + offset >= output + input)
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003334 break;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003335 if (*(b_peek(&chn->buf, offset + l)) == '\n') {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003336 len = l+1;
3337 goto dup;
3338 }
3339 }
3340
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003341 /* Wait for more data if possible if no line is found and no length was
3342 * specified or not enough data was received.
3343 */
3344 if (lua_gettop(L) != 3 || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003345 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3346 /* Yield waiting for more data */
3347 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_line_yield, TICK_ETERNITY, 0));
3348 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003349
3350 /* Return 'nil' if there is no data and the channel can't receive more data */
3351 if (!len) {
3352 lua_pushnil(L);
3353 return -1;
3354 }
3355
3356 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003357 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003358 }
3359
3360 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003361 _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003362 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003363}
3364
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003365/* [ DEPRECATED ]
3366 *
3367 * Duplicate all input data foud in the channel's buffer. The data are not
3368 * removed from the buffer. This function relies on _hlua_channel_dup().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003369 *
3370 * From an action, All input data are considered. For a filter, the offset and
3371 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003372 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003373__LJMP static int hlua_channel_dup(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003374{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003375 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003376 struct filter *filter;
3377 size_t offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003378
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003379 MAY_LJMP(check_args(L, 1, "dup"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003380 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003381 if (IS_HTX_STRM(chn_strm(chn))) {
3382 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3383 WILL_LJMP(lua_error(L));
3384 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003385
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003386 offset = co_data(chn);
3387 len = ci_data(chn);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003388
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003389 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3390 if (filter && !hlua_filter_from_payload(filter))
3391 WILL_LJMP(lua_error(L));
3392
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003393 if (!ci_data(chn) && channel_input_closed(chn)) {
3394 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003395 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003396 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003397
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003398 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003399 return 1;
3400}
3401
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003402/* [ DEPRECATED ]
3403 *
3404 * Get all input data foud in the channel's buffer. The data are removed from
3405 * the buffer after the copy. This function relies on _hlua_channel_dup() and
3406 * _hlua_channel_delete().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003407 *
3408 * From an action, All input data are considered. For a filter, the offset and
3409 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003410 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003411__LJMP static int hlua_channel_get(lua_State *L)
3412{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003413 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003414 struct filter *filter;
3415 size_t offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003416 int ret;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003417
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003418 MAY_LJMP(check_args(L, 1, "get"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003419 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3420 if (IS_HTX_STRM(chn_strm(chn))) {
3421 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3422 WILL_LJMP(lua_error(L));
3423 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003424
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003425 offset = co_data(chn);
3426 len = ci_data(chn);
3427
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003428 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3429 if (filter && !hlua_filter_from_payload(filter))
3430 WILL_LJMP(lua_error(L));
3431
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003432 if (!ci_data(chn) && channel_input_closed(chn)) {
3433 lua_pushnil(L);
3434 return 1;
3435 }
3436
3437 ret = _hlua_channel_dup(chn, L, offset, len);
3438 _hlua_channel_delete(chn, offset, ret);
3439 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003440}
3441
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003442/* This functions consumes and returns one line. If the channel is closed,
3443 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003444 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003445 * value.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003446 *
3447 * From an action, All input data are considered. For a filter, the offset and
3448 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003449 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003450__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003451{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003452 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003453 struct filter *filter;
3454 size_t l, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003455 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003456
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003457 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003458
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003459 offset = co_data(chn);
3460 len = ci_data(chn);
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003461
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003462 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3463 if (filter && !hlua_filter_from_payload(filter))
3464 WILL_LJMP(lua_error(L));
3465
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003466 if (!ci_data(chn) && channel_input_closed(chn)) {
3467 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003468 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003469 }
3470
3471 for (l = 0; l < len; l++) {
3472 if (*(b_peek(&chn->buf, offset+l)) == '\n') {
3473 len = l+1;
3474 goto dup;
3475 }
3476 }
3477
3478 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3479 /* Yield waiting for more data */
3480 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
3481 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003482
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003483 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003484 ret = _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003485 _hlua_channel_delete(chn, offset, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003486 return 1;
3487}
3488
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003489/* [ DEPRECATED ]
3490 *
3491 * Check arguments for the function "hlua_channel_getline_yield".
3492 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003493__LJMP static int hlua_channel_getline(lua_State *L)
3494{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003495 struct channel *chn;
3496
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003497 MAY_LJMP(check_args(L, 1, "getline"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003498 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3499 if (IS_HTX_STRM(chn_strm(chn))) {
3500 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3501 WILL_LJMP(lua_error(L));
3502 }
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003503 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3504}
3505
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003506/* Retrieves a given amount of input data at the given offset. By default all
3507 * available input data are returned. The offset may be negactive to start from
3508 * the end of input data. The length may be -1 to set it to the maximum buffer
3509 * size.
3510 */
3511__LJMP static int hlua_channel_get_data(lua_State *L)
3512{
3513 struct channel *chn;
3514
3515 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3516 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
3517 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3518 if (IS_HTX_STRM(chn_strm(chn))) {
3519 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3520 WILL_LJMP(lua_error(L));
3521 }
3522 return MAY_LJMP(hlua_channel_get_data_yield(L, 0, 0));
3523}
3524
3525/* Retrieves a given amount of input data at the given offset. By default all
3526 * available input data are returned. The offset may be negactive to start from
3527 * the end of input data. The length may be -1 to set it to the maximum buffer
3528 * size.
3529 */
3530__LJMP static int hlua_channel_get_line(lua_State *L)
3531{
3532 struct channel *chn;
3533
3534 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3535 WILL_LJMP(luaL_error(L, "'line' expects at most 2 arguments"));
3536 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3537 if (IS_HTX_STRM(chn_strm(chn))) {
3538 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3539 WILL_LJMP(lua_error(L));
3540 }
3541 return MAY_LJMP(hlua_channel_get_line_yield(L, 0, 0));
3542}
3543
3544/* Appends a string into the input side of channel. It returns the length of the
3545 * written string, or -1 if the channel is closed or if the buffer size is too
3546 * little for the data. 0 may be returned if nothing is copied. This function
3547 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003548 *
3549 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003550 */
Christopher Faulet23976d92021-08-06 09:59:49 +02003551__LJMP static int hlua_channel_append(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003552{
Christopher Faulet23976d92021-08-06 09:59:49 +02003553 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003554 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003555 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003556 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003557 int ret;
Christopher Faulet23976d92021-08-06 09:59:49 +02003558
3559 MAY_LJMP(check_args(L, 2, "append"));
3560 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003561 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003562 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003563 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003564 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003565 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003566
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003567 offset = co_data(chn);
3568 len = ci_data(chn);
3569
3570 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3571 if (filter && !hlua_filter_from_payload(filter))
3572 WILL_LJMP(lua_error(L));
3573
3574 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3575 if (ret > 0 && filter) {
3576 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3577
3578 flt_update_offsets(filter, chn, ret);
3579 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3580 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003581 lua_pushinteger(L, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003582 return 1;
3583}
3584
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003585/* Prepends a string into the input side of channel. It returns the length of the
3586 * written string, or -1 if the channel is closed or if the buffer size is too
3587 * little for the data. 0 may be returned if nothing is copied. This function
3588 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003589 *
3590 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003591 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003592__LJMP static int hlua_channel_prepend(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003593{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003594 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003595 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003596 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003597 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003598 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003599
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003600 MAY_LJMP(check_args(L, 2, "prepend"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003601 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003602 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3603 if (IS_HTX_STRM(chn_strm(chn))) {
3604 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3605 WILL_LJMP(lua_error(L));
3606 }
3607
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003608 offset = co_data(chn);
3609 len = ci_data(chn);
3610
3611 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3612 if (filter && !hlua_filter_from_payload(filter))
3613 WILL_LJMP(lua_error(L));
3614
3615 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3616 if (ret > 0 && filter) {
3617 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3618
3619 flt_update_offsets(filter, chn, ret);
3620 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3621 }
3622
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003623 lua_pushinteger(L, ret);
3624 return 1;
3625}
3626
3627/* Inserts a given amount of input data at the given offset by a string
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003628 * content. By default the string is appended in front of input data. It
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003629 * returns the length of the written string, or -1 if the channel is closed or
3630 * if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003631 *
3632 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003633 */
3634__LJMP static int hlua_channel_insert_data(lua_State *L)
3635{
3636 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003637 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003638 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003639 size_t sz, input, output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003640 int ret, offset;
3641
3642 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
3643 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
3644 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3645 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003646
3647 output = co_data(chn);
3648 input = ci_data(chn);
3649
3650 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3651 if (filter && !hlua_filter_from_payload(filter))
3652 WILL_LJMP(lua_error(L));
3653
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003654 offset = output;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003655 if (lua_gettop(L) > 2) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003656 offset = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003657 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003658 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003659 offset += output;
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003660 if (offset > output + input) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003661 lua_pushfstring(L, "offset out of range.");
3662 WILL_LJMP(lua_error(L));
3663 }
3664 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003665 if (IS_HTX_STRM(chn_strm(chn))) {
3666 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3667 WILL_LJMP(lua_error(L));
3668 }
3669
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003670 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3671 if (ret > 0 && filter) {
3672 struct hlua_flt_ctx *flt_ctx = filter->ctx;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003673
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003674 flt_update_offsets(filter, chn, ret);
3675 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003676 }
3677
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003678 lua_pushinteger(L, ret);
3679 return 1;
3680}
3681/* Replaces a given amount of input data at the given offset by a string
3682 * content. By default all remaining data are removed (offset = 0 and len =
3683 * -1). It returns the length of the written string, or -1 if the channel is
3684 * closed or if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003685 *
3686 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003687 */
3688__LJMP static int hlua_channel_set_data(lua_State *L)
3689{
3690 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003691 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003692 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003693 size_t sz, input, output;
3694 int ret, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003695
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003696 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
3697 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
3698 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3699 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003700
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003701 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003702 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003703 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003704 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003705
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003706 output = co_data(chn);
3707 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003708
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003709 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3710 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003711 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003712
3713 offset = output;
3714 if (lua_gettop(L) > 2) {
3715 offset = MAY_LJMP(luaL_checkinteger(L, 3));
3716 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003717 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003718 offset += output;
3719 if (offset < output || offset > input + output) {
3720 lua_pushfstring(L, "offset out of range.");
3721 WILL_LJMP(lua_error(L));
3722 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003723 }
3724
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003725 len = output + input - offset;
3726 if (lua_gettop(L) == 4) {
3727 len = MAY_LJMP(luaL_checkinteger(L, 4));
3728 if (!len)
3729 goto set;
3730 if (len == -1)
3731 len = output + input - offset;
3732 if (len < 0 || offset + len > output + input) {
3733 lua_pushfstring(L, "length out of range.");
3734 WILL_LJMP(lua_error(L));
3735 }
3736 }
3737
3738 set:
Christopher Faulet23976d92021-08-06 09:59:49 +02003739 /* Be sure we can copied the string once input data will be removed. */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003740 if (sz > c_room(chn) + len)
Christopher Faulet23976d92021-08-06 09:59:49 +02003741 lua_pushinteger(L, -1);
3742 else {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003743 _hlua_channel_delete(chn, offset, len);
3744 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3745 if (filter) {
3746 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3747
3748 len -= (ret > 0 ? ret : 0);
3749 flt_update_offsets(filter, chn, -len);
3750 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3751 }
3752
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003753 lua_pushinteger(L, ret);
Christopher Faulet23976d92021-08-06 09:59:49 +02003754 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003755 return 1;
3756}
3757
3758/* Removes a given amount of input data at the given offset. By default all
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003759 * input data are removed (offset = 0 and len = -1). It returns the amount of
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003760 * the removed data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003761 *
3762 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003763 */
3764__LJMP static int hlua_channel_del_data(lua_State *L)
3765{
3766 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003767 struct filter *filter;
3768 size_t input, output;
3769 int offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003770
3771 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3772 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
3773 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003774
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003775 if (IS_HTX_STRM(chn_strm(chn))) {
3776 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3777 WILL_LJMP(lua_error(L));
3778 }
3779
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003780 output = co_data(chn);
3781 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003782
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003783 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3784 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003785 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003786
3787 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00003788 if (lua_gettop(L) > 1) {
3789 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003790 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003791 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003792 offset += output;
3793 if (offset < output || offset > input + output) {
3794 lua_pushfstring(L, "offset out of range.");
3795 WILL_LJMP(lua_error(L));
3796 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003797 }
3798
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003799 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00003800 if (lua_gettop(L) == 3) {
3801 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003802 if (!len)
3803 goto end;
3804 if (len == -1)
3805 len = output + input - offset;
3806 if (len < 0 || offset + len > output + input) {
3807 lua_pushfstring(L, "length out of range.");
3808 WILL_LJMP(lua_error(L));
3809 }
3810 }
3811
3812 _hlua_channel_delete(chn, offset, len);
3813 if (filter) {
3814 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3815
3816 flt_update_offsets(filter, chn, -len);
3817 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3818 }
3819
3820 end:
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003821 lua_pushinteger(L, len);
Christopher Faulet23976d92021-08-06 09:59:49 +02003822 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003823}
3824
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003825/* Append data in the output side of the buffer. This data is immediately
3826 * sent. The function returns the amount of data written. If the buffer
3827 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003828 * if the channel is closed.
3829 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003830__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003831{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003832 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003833 struct filter *filter;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003834 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003835 size_t offset, len, sz;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003836 int l, ret;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003837 struct hlua *hlua;
3838
3839 /* Get hlua struct, or NULL if we execute from main lua state */
3840 hlua = hlua_gethlua(L);
3841 if (!hlua) {
3842 lua_pushnil(L);
3843 return 1;
3844 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003845
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003846 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3847 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3848 l = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003849
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003850 offset = co_data(chn);
3851 len = ci_data(chn);
3852
3853 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3854 if (filter && !hlua_filter_from_payload(filter))
3855 WILL_LJMP(lua_error(L));
3856
3857
Willy Tarreau47860ed2015-03-10 14:07:50 +01003858 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003859 lua_pushinteger(L, -1);
3860 return 1;
3861 }
3862
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003863 len = c_room(chn);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003864 if (len > sz -l) {
3865 if (filter) {
3866 lua_pushinteger(L, -1);
3867 return 1;
3868 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003869 len = sz - l;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003870 }
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003871
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003872 ret = _hlua_channel_insert(chn, L, ist2(str, len), offset);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003873 if (ret == -1) {
3874 lua_pop(L, 1);
3875 lua_pushinteger(L, -1);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003876 return 1;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003877 }
3878 if (ret) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003879 if (filter) {
3880 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3881
3882
3883 flt_update_offsets(filter, chn, ret);
3884 FLT_OFF(filter, chn) += ret;
3885 flt_ctx->cur_off[CHN_IDX(chn)] += ret;
3886 }
3887 else
3888 c_adv(chn, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003889
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003890 l += ret;
3891 lua_pop(L, 1);
3892 lua_pushinteger(L, l);
3893 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003894
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003895 if (l < sz) {
3896 /* Yield only if the channel's output is not empty.
3897 * Otherwise it means we cannot add more data. */
3898 if (co_data(chn) == 0 || HLUA_CANT_YIELD(hlua_gethlua(L)))
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003899 return 1;
3900
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003901 /* If we are waiting for space in the response buffer, we
3902 * must set the flag WAKERESWR. This flag required the task
3903 * wake up if any activity is detected on the response buffer.
3904 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003905 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003906 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003907 else
3908 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003909 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003910 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003911
3912 return 1;
3913}
3914
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003915/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003916 * yield the LUA process, and resume it without checking the
3917 * input arguments.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003918 *
3919 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003920 */
3921__LJMP static int hlua_channel_send(lua_State *L)
3922{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003923 struct channel *chn;
3924
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003925 MAY_LJMP(check_args(L, 2, "send"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003926 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3927 if (IS_HTX_STRM(chn_strm(chn))) {
3928 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3929 WILL_LJMP(lua_error(L));
3930 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003931 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003932 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003933}
3934
3935/* This function forward and amount of butes. The data pass from
3936 * the input side of the buffer to the output side, and can be
3937 * forwarded. This function never fails.
3938 *
3939 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003940 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003941 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003942__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003943{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003944 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003945 struct filter *filter;
3946 size_t offset, len, fwd;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003947 int l, max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003948 struct hlua *hlua;
3949
3950 /* Get hlua struct, or NULL if we execute from main lua state */
3951 hlua = hlua_gethlua(L);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003952 if (!hlua) {
3953 lua_pushnil(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003954 return 1;
Thierry Fournier77016da2020-08-15 14:35:51 +02003955 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003956
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003957 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003958 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003959 l = MAY_LJMP(luaL_checkinteger(L, -1));
3960
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003961 offset = co_data(chn);
3962 len = ci_data(chn);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003963
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003964 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3965 if (filter && !hlua_filter_from_payload(filter))
3966 WILL_LJMP(lua_error(L));
3967
3968 max = fwd - l;
3969 if (max > len)
3970 max = len;
3971
3972 if (filter) {
3973 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3974
3975 FLT_OFF(filter, chn) += max;
3976 flt_ctx->cur_off[CHN_IDX(chn)] += max;
3977 flt_ctx->cur_len[CHN_IDX(chn)] -= max;
3978 }
3979 else
3980 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003981
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003982 l += max;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003983 lua_pop(L, 1);
3984 lua_pushinteger(L, l);
3985
3986 /* Check if it miss bytes to forward. */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003987 if (l < fwd) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003988 /* The the input channel or the output channel are closed, we
3989 * must return the amount of data forwarded.
3990 */
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003991 if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L)))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003992 return 1;
3993
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003994 /* If we are waiting for space data in the response buffer, we
3995 * must set the flag WAKERESWR. This flag required the task
3996 * wake up if any activity is detected on the response buffer.
3997 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003998 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003999 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01004000 else
4001 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004002
Ilya Shipitsin4a689da2022-10-29 09:34:32 +05004003 /* Otherwise, we can yield waiting for new data in the input side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02004004 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004005 }
4006
4007 return 1;
4008}
4009
4010/* Just check the input and prepare the stack for the previous
4011 * function "hlua_channel_forward_yield"
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004012 *
4013 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004014 */
4015__LJMP static int hlua_channel_forward(lua_State *L)
4016{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004017 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004018
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004019 MAY_LJMP(check_args(L, 2, "forward"));
4020 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4021 if (IS_HTX_STRM(chn_strm(chn))) {
4022 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
4023 WILL_LJMP(lua_error(L));
4024 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004025 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004026 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004027}
4028
4029/* Just returns the number of bytes available in the input
4030 * side of the buffer. This function never fails.
4031 */
4032__LJMP static int hlua_channel_get_in_len(lua_State *L)
4033{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004034 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004035 struct filter *filter;
4036 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004037
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004038 MAY_LJMP(check_args(L, 1, "input"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004039 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004040
4041 output = co_data(chn);
4042 input = ci_data(chn);
4043 filter = hlua_channel_filter(L, 1, chn, &output, &input);
4044 if (filter || !IS_HTX_STRM(chn_strm(chn)))
4045 lua_pushinteger(L, input);
4046 else {
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004047 struct htx *htx = htxbuf(&chn->buf);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004048
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004049 lua_pushinteger(L, htx->data - co_data(chn));
4050 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004051 return 1;
4052}
4053
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004054/* Returns true if the channel is full. */
4055__LJMP static int hlua_channel_is_full(lua_State *L)
4056{
4057 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004058
4059 MAY_LJMP(check_args(L, 1, "is_full"));
4060 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01004061 /* ignore the reserve, we are not on a producer side (ie in an
4062 * applet).
4063 */
4064 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004065 return 1;
4066}
4067
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004068/* Returns true if the channel may still receive data. */
4069__LJMP static int hlua_channel_may_recv(lua_State *L)
4070{
4071 struct channel *chn;
4072
4073 MAY_LJMP(check_args(L, 1, "may_recv"));
4074 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4075 lua_pushboolean(L, (!channel_input_closed(chn) && channel_may_recv(chn)));
4076 return 1;
4077}
4078
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01004079/* Returns true if the channel is the response channel. */
4080__LJMP static int hlua_channel_is_resp(lua_State *L)
4081{
4082 struct channel *chn;
4083
4084 MAY_LJMP(check_args(L, 1, "is_resp"));
4085 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4086
4087 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
4088 return 1;
4089}
4090
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004091/* Just returns the number of bytes available in the output
4092 * side of the buffer. This function never fails.
4093 */
4094__LJMP static int hlua_channel_get_out_len(lua_State *L)
4095{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004096 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004097 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004098
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004099 MAY_LJMP(check_args(L, 1, "output"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004100 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004101
4102 output = co_data(chn);
4103 input = ci_data(chn);
4104 hlua_channel_filter(L, 1, chn, &output, &input);
4105
4106 lua_pushinteger(L, output);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004107 return 1;
4108}
4109
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004110/*
4111 *
4112 *
4113 * Class Fetches
4114 *
4115 *
4116 */
4117
4118/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004119 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004120 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004121__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004122{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004123 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004124}
4125
4126/* This function creates and push in the stack a fetch object according
4127 * with a current TXN.
4128 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004129static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004130{
Willy Tarreau7073c472015-04-06 11:15:40 +02004131 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004132
4133 /* Check stack size. */
4134 if (!lua_checkstack(L, 3))
4135 return 0;
4136
4137 /* Create the object: obj[0] = userdata.
4138 * Note that the base of the Fetches object is the
4139 * transaction object.
4140 */
4141 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004142 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004143 lua_rawseti(L, -2, 0);
4144
Willy Tarreau7073c472015-04-06 11:15:40 +02004145 hsmp->s = txn->s;
4146 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004147 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004148 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004149
4150 /* Pop a class sesison metatable and affect it to the userdata. */
4151 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
4152 lua_setmetatable(L, -2);
4153
4154 return 1;
4155}
4156
4157/* This function is an LUA binding. It is called with each sample-fetch.
4158 * It uses closure argument to store the associated sample-fetch. It
4159 * returns only one argument or throws an error. An error is thrown
4160 * only if an error is encountered during the argument parsing. If
4161 * the "sample-fetch" function fails, nil is returned.
4162 */
4163__LJMP static int hlua_run_sample_fetch(lua_State *L)
4164{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004165 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01004166 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004167 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004168 int i;
4169 struct sample smp;
4170
4171 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004172 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004173
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004174 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004175 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004176
Thierry FOURNIERca988662015-12-20 18:43:03 +01004177 /* Check execution authorization. */
4178 if (f->use & SMP_USE_HTTP_ANY &&
4179 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
4180 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
4181 "is not available in Lua services", f->kw);
4182 WILL_LJMP(lua_error(L));
4183 }
4184
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004185 /* Get extra arguments. */
4186 for (i = 0; i < lua_gettop(L) - 1; i++) {
4187 if (i >= ARGM_NBARGS)
4188 break;
4189 hlua_lua2arg(L, i + 2, &args[i]);
4190 }
4191 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004192 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004193
4194 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004195 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004196
4197 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01004198 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004199 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004200 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004201 }
4202
4203 /* Initialise the sample. */
4204 memset(&smp, 0, sizeof(smp));
4205
4206 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01004207 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02004208 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004209 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004210 lua_pushstring(L, "");
4211 else
4212 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004213 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004214 }
4215
4216 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004217 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004218 hlua_smp2lua_str(L, &smp);
4219 else
4220 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004221
4222 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004223 free_args(args);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004224 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004225
4226 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004227 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004228 WILL_LJMP(lua_error(L));
4229 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004230}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004231
4232/*
4233 *
4234 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004235 * Class Converters
4236 *
4237 *
4238 */
4239
4240/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004241 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004242 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004243__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004244{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004245 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004246}
4247
4248/* This function creates and push in the stack a Converters object
4249 * according with a current TXN.
4250 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004251static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004252{
Willy Tarreau7073c472015-04-06 11:15:40 +02004253 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004254
4255 /* Check stack size. */
4256 if (!lua_checkstack(L, 3))
4257 return 0;
4258
4259 /* Create the object: obj[0] = userdata.
4260 * Note that the base of the Converters object is the
4261 * same than the TXN object.
4262 */
4263 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004264 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004265 lua_rawseti(L, -2, 0);
4266
Willy Tarreau7073c472015-04-06 11:15:40 +02004267 hsmp->s = txn->s;
4268 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004269 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004270 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004271
Willy Tarreau87b09662015-04-03 00:22:06 +02004272 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004273 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
4274 lua_setmetatable(L, -2);
4275
4276 return 1;
4277}
4278
4279/* This function is an LUA binding. It is called with each converter.
4280 * It uses closure argument to store the associated converter. It
4281 * returns only one argument or throws an error. An error is thrown
4282 * only if an error is encountered during the argument parsing. If
4283 * the converter function function fails, nil is returned.
4284 */
4285__LJMP static int hlua_run_sample_conv(lua_State *L)
4286{
Willy Tarreauda5f1082015-04-06 11:17:13 +02004287 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004288 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004289 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004290 int i;
4291 struct sample smp;
4292
4293 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004294 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004295
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004296 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004297 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004298
4299 /* Get extra arguments. */
4300 for (i = 0; i < lua_gettop(L) - 2; i++) {
4301 if (i >= ARGM_NBARGS)
4302 break;
4303 hlua_lua2arg(L, i + 3, &args[i]);
4304 }
4305 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004306 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004307
4308 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004309 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004310
4311 /* Run the special args checker. */
4312 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
4313 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004314 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004315 }
4316
4317 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004318 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004319 if (!hlua_lua2smp(L, 2, &smp)) {
4320 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004321 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004322 }
4323
Willy Tarreau1777ea62016-03-10 16:15:46 +01004324 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
4325
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004326 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004327 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004328 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004329 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004330 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004331 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004332 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
4333 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004334 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004335 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004336 }
4337
4338 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02004339 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004340 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004341 lua_pushstring(L, "");
4342 else
Willy Tarreaua678b432015-08-28 10:14:59 +02004343 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004344 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004345 }
4346
4347 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004348 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004349 hlua_smp2lua_str(L, &smp);
4350 else
4351 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004352 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004353 free_args(args);
Willy Tarreaua678b432015-08-28 10:14:59 +02004354 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004355
4356 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004357 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004358 WILL_LJMP(lua_error(L));
4359 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004360}
4361
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004362/*
4363 *
4364 *
4365 * Class AppletTCP
4366 *
4367 *
4368 */
4369
4370/* Returns a struct hlua_txn if the stack entry "ud" is
4371 * a class stream, otherwise it throws an error.
4372 */
4373__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
4374{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004375 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004376}
4377
4378/* This function creates and push in the stack an Applet object
4379 * according with a current TXN.
4380 */
4381static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
4382{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004383 struct hlua_appctx *luactx;
Willy Tarreau0698c802022-05-11 14:09:57 +02004384 struct stream *s = appctx_strm(ctx);
Christopher Faulet2da02ae2022-02-24 13:45:27 +01004385 struct proxy *p;
4386
4387 ALREADY_CHECKED(s);
4388 p = s->be;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004389
4390 /* Check stack size. */
4391 if (!lua_checkstack(L, 3))
4392 return 0;
4393
4394 /* Create the object: obj[0] = userdata.
4395 * Note that the base of the Converters object is the
4396 * same than the TXN object.
4397 */
4398 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004399 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004400 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004401 luactx->appctx = ctx;
4402 luactx->htxn.s = s;
4403 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004404
4405 /* Create the "f" field that contains a list of fetches. */
4406 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004407 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004408 return 0;
4409 lua_settable(L, -3);
4410
4411 /* Create the "sf" field that contains a list of stringsafe fetches. */
4412 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004413 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004414 return 0;
4415 lua_settable(L, -3);
4416
4417 /* Create the "c" field that contains a list of converters. */
4418 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004419 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004420 return 0;
4421 lua_settable(L, -3);
4422
4423 /* Create the "sc" field that contains a list of stringsafe converters. */
4424 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004425 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004426 return 0;
4427 lua_settable(L, -3);
4428
4429 /* Pop a class stream metatable and affect it to the table. */
4430 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
4431 lua_setmetatable(L, -2);
4432
4433 return 1;
4434}
4435
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004436__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
4437{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004438 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004439 struct stream *s;
4440 const char *name;
4441 size_t len;
4442 struct sample smp;
4443
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004444 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4445 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004446
4447 /* It is useles to retrieve the stream, but this function
4448 * runs only in a stream context.
4449 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004450 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004451 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004452 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004453
4454 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004455 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004456 hlua_lua2smp(L, 3, &smp);
4457
4458 /* Store the sample in a variable. */
4459 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004460
4461 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4462 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4463 else
4464 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4465
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004466 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004467}
4468
4469__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
4470{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004471 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004472 struct stream *s;
4473 const char *name;
4474 size_t len;
4475 struct sample smp;
4476
4477 MAY_LJMP(check_args(L, 2, "unset_var"));
4478
4479 /* It is useles to retrieve the stream, but this function
4480 * runs only in a stream context.
4481 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004482 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004483 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004484 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004485
4486 /* Unset the variable. */
4487 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004488 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4489 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004490}
4491
4492__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
4493{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004494 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004495 struct stream *s;
4496 const char *name;
4497 size_t len;
4498 struct sample smp;
4499
4500 MAY_LJMP(check_args(L, 2, "get_var"));
4501
4502 /* It is useles to retrieve the stream, but this function
4503 * runs only in a stream context.
4504 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004505 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004506 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004507 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004508
4509 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02004510 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004511 lua_pushnil(L);
4512 return 1;
4513 }
4514
4515 return hlua_smp2lua(L, &smp);
4516}
4517
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004518__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
4519{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004520 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4521 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004522 struct hlua *hlua;
4523
4524 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004525 if (!s->hlua)
4526 return 0;
4527 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004528
4529 MAY_LJMP(check_args(L, 2, "set_priv"));
4530
4531 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004532 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004533
4534 /* Get and store new value. */
4535 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4536 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4537
4538 return 0;
4539}
4540
4541__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
4542{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004543 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4544 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004545 struct hlua *hlua;
4546
4547 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004548 if (!s->hlua) {
4549 lua_pushnil(L);
4550 return 1;
4551 }
4552 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004553
4554 /* Push configuration index in the stack. */
4555 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4556
4557 return 1;
4558}
4559
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004560/* If expected data not yet available, it returns a yield. This function
4561 * consumes the data in the buffer. It returns a string containing the
4562 * data. This string can be empty.
4563 */
4564__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
4565{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004566 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004567 struct stconn *sc = appctx_sc(luactx->appctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004568 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004569 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004570 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004571 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004572 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004573
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004574 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004575 ret = co_getline_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004576
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004577 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004578 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004579 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004580 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004581 }
4582
4583 /* End of data: commit the total strings and return. */
4584 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004585 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004586 return 1;
4587 }
4588
4589 /* Ensure that the block 2 length is usable. */
4590 if (ret == 1)
4591 len2 = 0;
4592
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004593 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004594 luaL_addlstring(&luactx->b, blk1, len1);
4595 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004596
4597 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004598 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004599 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004600 return 1;
4601}
4602
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004603/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004604__LJMP static int hlua_applet_tcp_getline(lua_State *L)
4605{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004606 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004607
4608 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004609 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004610
4611 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
4612}
4613
4614/* If expected data not yet available, it returns a yield. This function
4615 * consumes the data in the buffer. It returns a string containing the
4616 * data. This string can be empty.
4617 */
4618__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
4619{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004620 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004621 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004622 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004623 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004624 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004625 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004626 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004627 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004628
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004629 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004630 ret = co_getblk_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004631
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004632 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004633 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004634 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004635 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004636 }
4637
4638 /* End of data: commit the total strings and return. */
4639 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004640 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004641 return 1;
4642 }
4643
4644 /* Ensure that the block 2 length is usable. */
4645 if (ret == 1)
4646 len2 = 0;
4647
4648 if (len == -1) {
4649
4650 /* If len == -1, catenate all the data avalaile and
4651 * yield because we want to get all the data until
4652 * the end of data stream.
4653 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004654 luaL_addlstring(&luactx->b, blk1, len1);
4655 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004656 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004657 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004658 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004659
4660 } else {
4661
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004662 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004663 if (len1 > len)
4664 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004665 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004666 len -= len1;
4667
4668 /* Copy the second block. */
4669 if (len2 > len)
4670 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004671 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004672 len -= len2;
4673
4674 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004675 co_skip(sc_oc(sc), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004676
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004677 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004678 if (len > 0) {
4679 lua_pushinteger(L, len);
4680 lua_replace(L, 2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004681 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004682 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004683 }
4684
4685 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004686 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004687 return 1;
4688 }
4689
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004690 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004691 hlua_pusherror(L, "Lua: internal error");
4692 WILL_LJMP(lua_error(L));
4693 return 0;
4694}
4695
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004696/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004697__LJMP static int hlua_applet_tcp_recv(lua_State *L)
4698{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004699 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004700 int len = -1;
4701
4702 if (lua_gettop(L) > 2)
4703 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4704 if (lua_gettop(L) >= 2) {
4705 len = MAY_LJMP(luaL_checkinteger(L, 2));
4706 lua_pop(L, 1);
4707 }
4708
4709 /* Confirm or set the required length */
4710 lua_pushinteger(L, len);
4711
4712 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004713 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004714
4715 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
4716}
4717
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004718/* Append data in the output side of the buffer. This data is immediately
4719 * sent. The function returns the amount of data written. If the buffer
4720 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004721 * if the channel is closed.
4722 */
4723__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4724{
4725 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004726 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004727 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4728 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004729 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004730 struct channel *chn = sc_ic(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004731 int max;
4732
4733 /* Get the max amount of data which can write as input in the channel. */
4734 max = channel_recv_max(chn);
4735 if (max > (len - l))
4736 max = len - l;
4737
4738 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004739 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004740
4741 /* update counters. */
4742 l += max;
4743 lua_pop(L, 1);
4744 lua_pushinteger(L, l);
4745
4746 /* If some data is not send, declares the situation to the
4747 * applet, and returns a yield.
4748 */
4749 if (l < len) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02004750 sc_need_room(sc);
Willy Tarreau9635e032018-10-16 17:52:55 +02004751 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004752 }
4753
4754 return 1;
4755}
4756
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004757/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004758 * yield the LUA process, and resume it without checking the
4759 * input arguments.
4760 */
4761__LJMP static int hlua_applet_tcp_send(lua_State *L)
4762{
4763 MAY_LJMP(check_args(L, 2, "send"));
4764 lua_pushinteger(L, 0);
4765
4766 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
4767}
4768
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004769/*
4770 *
4771 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004772 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004773 *
4774 *
4775 */
4776
4777/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004778 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004779 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004780__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004781{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004782 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004783}
4784
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004785/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004786 * according with a current TXN.
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004787 * It relies on the caller to have already reserved the room in ctx->svcctx
4788 * for the local storage of hlua_http_ctx.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004789 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004790static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004791{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004792 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004793 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01004794 struct hlua_txn htxn;
Willy Tarreau0698c802022-05-11 14:09:57 +02004795 struct stream *s = appctx_strm(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004796 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02004797 struct htx *htx;
4798 struct htx_blk *blk;
4799 struct htx_sl *sl;
4800 struct ist path;
4801 unsigned long long len = 0;
4802 int32_t pos;
Amaury Denoyellec453f952021-07-06 11:40:12 +02004803 struct http_uri_parser parser;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004804
4805 /* Check stack size. */
4806 if (!lua_checkstack(L, 3))
4807 return 0;
4808
4809 /* Create the object: obj[0] = userdata.
4810 * Note that the base of the Converters object is the
4811 * same than the TXN object.
4812 */
4813 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004814 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004815 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004816 luactx->appctx = ctx;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004817 http_ctx->status = 200; /* Default status code returned. */
4818 http_ctx->reason = NULL; /* Use default reason based on status */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004819 luactx->htxn.s = s;
4820 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004821
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004822 /* Create the "f" field that contains a list of fetches. */
4823 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004824 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004825 return 0;
4826 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004827
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004828 /* Create the "sf" field that contains a list of stringsafe fetches. */
4829 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004830 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004831 return 0;
4832 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004833
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004834 /* Create the "c" field that contains a list of converters. */
4835 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004836 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004837 return 0;
4838 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004839
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004840 /* Create the "sc" field that contains a list of stringsafe converters. */
4841 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004842 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004843 return 0;
4844 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004845
Christopher Fauleta2097962019-07-15 16:25:33 +02004846 htx = htxbuf(&s->req.buf);
4847 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004848 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004849 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004850
Christopher Fauleta2097962019-07-15 16:25:33 +02004851 /* Stores the request method. */
4852 lua_pushstring(L, "method");
4853 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4854 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004855
Christopher Fauleta2097962019-07-15 16:25:33 +02004856 /* Stores the http version. */
4857 lua_pushstring(L, "version");
4858 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4859 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004860
Christopher Fauleta2097962019-07-15 16:25:33 +02004861 /* creates an array of headers. hlua_http_get_headers() crates and push
4862 * the array on the top of the stack.
4863 */
4864 lua_pushstring(L, "headers");
4865 htxn.s = s;
4866 htxn.p = px;
4867 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004868 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004869 return 0;
4870 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004871
Amaury Denoyellec453f952021-07-06 11:40:12 +02004872 parser = http_uri_parser_init(htx_sl_req_uri(sl));
4873 path = http_parse_path(&parser);
Tim Duesterhused526372020-03-05 17:56:33 +01004874 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004875 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004876
Christopher Fauleta2097962019-07-15 16:25:33 +02004877 p = path.ptr;
Tim Duesterhus4c8f75f2021-11-06 15:14:44 +01004878 end = istend(path);
Christopher Fauleta2097962019-07-15 16:25:33 +02004879 q = p;
4880 while (q < end && *q != '?')
4881 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004882
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004883 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004884 lua_pushstring(L, "path");
4885 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004886 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004887
Christopher Fauleta2097962019-07-15 16:25:33 +02004888 /* Stores the query string. */
4889 lua_pushstring(L, "qs");
4890 if (*q == '?')
4891 q++;
4892 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004893 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004894 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004895
Christopher Fauleta2097962019-07-15 16:25:33 +02004896 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4897 struct htx_blk *blk = htx_get_blk(htx, pos);
4898 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004899
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004900 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02004901 break;
4902 if (type == HTX_BLK_DATA)
4903 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004904 }
Christopher Faulet2e47e3a2023-01-13 11:40:24 +01004905 if (htx->extra != HTX_UNKOWN_PAYLOAD_LENGTH)
Christopher Fauleta2097962019-07-15 16:25:33 +02004906 len += htx->extra;
4907
4908 /* Stores the request path. */
4909 lua_pushstring(L, "length");
4910 lua_pushinteger(L, len);
4911 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004912
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004913 /* Create an empty array of HTTP request headers. */
4914 lua_pushstring(L, "response");
4915 lua_newtable(L);
4916 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004917
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004918 /* Pop a class stream metatable and affect it to the table. */
4919 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4920 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004921
4922 return 1;
4923}
4924
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004925__LJMP static int hlua_applet_http_set_var(lua_State *L)
4926{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004927 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004928 struct stream *s;
4929 const char *name;
4930 size_t len;
4931 struct sample smp;
4932
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004933 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4934 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004935
4936 /* It is useles to retrieve the stream, but this function
4937 * runs only in a stream context.
4938 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004939 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004940 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004941 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004942
4943 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004944 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004945 hlua_lua2smp(L, 3, &smp);
4946
4947 /* Store the sample in a variable. */
4948 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004949
4950 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4951 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4952 else
4953 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4954
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004955 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004956}
4957
4958__LJMP static int hlua_applet_http_unset_var(lua_State *L)
4959{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004960 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004961 struct stream *s;
4962 const char *name;
4963 size_t len;
4964 struct sample smp;
4965
4966 MAY_LJMP(check_args(L, 2, "unset_var"));
4967
4968 /* It is useles to retrieve the stream, but this function
4969 * runs only in a stream context.
4970 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004971 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004972 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004973 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004974
4975 /* Unset the variable. */
4976 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004977 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4978 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004979}
4980
4981__LJMP static int hlua_applet_http_get_var(lua_State *L)
4982{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004983 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004984 struct stream *s;
4985 const char *name;
4986 size_t len;
4987 struct sample smp;
4988
4989 MAY_LJMP(check_args(L, 2, "get_var"));
4990
4991 /* It is useles to retrieve the stream, but this function
4992 * runs only in a stream context.
4993 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004994 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004995 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004996 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004997
4998 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02004999 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005000 lua_pushnil(L);
5001 return 1;
5002 }
5003
5004 return hlua_smp2lua(L, &smp);
5005}
5006
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005007__LJMP static int hlua_applet_http_set_priv(lua_State *L)
5008{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005009 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5010 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005011 struct hlua *hlua;
5012
5013 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005014 if (!s->hlua)
5015 return 0;
5016 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005017
5018 MAY_LJMP(check_args(L, 2, "set_priv"));
5019
5020 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005021 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005022
5023 /* Get and store new value. */
5024 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5025 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5026
5027 return 0;
5028}
5029
5030__LJMP static int hlua_applet_http_get_priv(lua_State *L)
5031{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005032 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5033 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005034 struct hlua *hlua;
5035
5036 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005037 if (!s->hlua) {
5038 lua_pushnil(L);
5039 return 1;
5040 }
5041 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005042
5043 /* Push configuration index in the stack. */
5044 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5045
5046 return 1;
5047}
5048
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005049/* If expected data not yet available, it returns a yield. This function
5050 * consumes the data in the buffer. It returns a string containing the
5051 * data. This string can be empty.
5052 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005053__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005054{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005055 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005056 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005057 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005058 struct htx *htx;
5059 struct htx_blk *blk;
5060 size_t count;
5061 int stop = 0;
5062
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005063 htx = htx_from_buf(&req->buf);
5064 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02005065 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01005066
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005067 while (count && !stop && blk) {
5068 enum htx_blk_type type = htx_get_blk_type(blk);
5069 uint32_t sz = htx_get_blksz(blk);
5070 struct ist v;
5071 uint32_t vlen;
5072 char *nl;
5073
5074 vlen = sz;
5075 if (vlen > count) {
5076 if (type != HTX_BLK_DATA)
5077 break;
5078 vlen = count;
5079 }
5080
5081 switch (type) {
5082 case HTX_BLK_UNUSED:
5083 break;
5084
5085 case HTX_BLK_DATA:
5086 v = htx_get_blk_value(htx, blk);
5087 v.len = vlen;
5088 nl = istchr(v, '\n');
5089 if (nl != NULL) {
5090 stop = 1;
5091 vlen = nl - v.ptr + 1;
5092 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02005093 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005094 break;
5095
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005096 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005097 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005098 stop = 1;
5099 break;
5100
5101 default:
5102 break;
5103 }
5104
Willy Tarreau84240042022-02-28 16:51:23 +01005105 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005106 count -= vlen;
5107 if (sz == vlen)
5108 blk = htx_remove_blk(htx, blk);
5109 else {
5110 htx_cut_data_blk(htx, blk, vlen);
5111 break;
5112 }
5113 }
5114
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005115 /* The message was fully consumed and no more data are expected
5116 * (EOM flag set).
5117 */
Christopher Faulet4a209722022-08-29 15:37:16 +02005118 if (htx_is_empty(htx) && (req->flags & CF_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005119 stop = 1;
5120
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005121 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005122 if (!stop) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02005123 applet_need_more_data(luactx->appctx);
Christopher Fauleta2097962019-07-15 16:25:33 +02005124 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005125 }
5126
5127 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005128 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005129 return 1;
5130}
5131
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005132
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005133/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005134__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005135{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005136 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005137
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005138 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005139 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005140
Christopher Fauleta2097962019-07-15 16:25:33 +02005141 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005142}
5143
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005144/* If expected data not yet available, it returns a yield. This function
5145 * consumes the data in the buffer. It returns a string containing the
5146 * data. This string can be empty.
5147 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005148__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005149{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005150 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005151 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005152 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005153 struct htx *htx;
5154 struct htx_blk *blk;
5155 size_t count;
5156 int len;
5157
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005158 htx = htx_from_buf(&req->buf);
5159 len = MAY_LJMP(luaL_checkinteger(L, 2));
5160 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02005161 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005162 while (count && len && blk) {
5163 enum htx_blk_type type = htx_get_blk_type(blk);
5164 uint32_t sz = htx_get_blksz(blk);
5165 struct ist v;
5166 uint32_t vlen;
5167
5168 vlen = sz;
5169 if (len > 0 && vlen > len)
5170 vlen = len;
5171 if (vlen > count) {
5172 if (type != HTX_BLK_DATA)
5173 break;
5174 vlen = count;
5175 }
5176
5177 switch (type) {
5178 case HTX_BLK_UNUSED:
5179 break;
5180
5181 case HTX_BLK_DATA:
5182 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02005183 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005184 break;
5185
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005186 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005187 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005188 len = 0;
5189 break;
5190
5191 default:
5192 break;
5193 }
5194
Willy Tarreau84240042022-02-28 16:51:23 +01005195 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005196 count -= vlen;
5197 if (len > 0)
5198 len -= vlen;
5199 if (sz == vlen)
5200 blk = htx_remove_blk(htx, blk);
5201 else {
5202 htx_cut_data_blk(htx, blk, vlen);
5203 break;
5204 }
5205 }
5206
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005207 /* The message was fully consumed and no more data are expected
5208 * (EOM flag set).
5209 */
Christopher Faulet4a209722022-08-29 15:37:16 +02005210 if (htx_is_empty(htx) && (req->flags & CF_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005211 len = 0;
5212
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005213 htx_to_buf(htx, &req->buf);
5214
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005215 /* If we are no other data available, yield waiting for new data. */
5216 if (len) {
5217 if (len > 0) {
5218 lua_pushinteger(L, len);
5219 lua_replace(L, 2);
5220 }
Willy Tarreau90e8b452022-05-25 18:21:43 +02005221 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02005222 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005223 }
5224
5225 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005226 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005227 return 1;
5228}
5229
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005230/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005231__LJMP static int hlua_applet_http_recv(lua_State *L)
5232{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005233 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005234 int len = -1;
5235
5236 /* Check arguments. */
5237 if (lua_gettop(L) > 2)
5238 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
5239 if (lua_gettop(L) >= 2) {
5240 len = MAY_LJMP(luaL_checkinteger(L, 2));
5241 lua_pop(L, 1);
5242 }
5243
Christopher Fauleta2097962019-07-15 16:25:33 +02005244 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005245
Christopher Fauleta2097962019-07-15 16:25:33 +02005246 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005247 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005248
Christopher Fauleta2097962019-07-15 16:25:33 +02005249 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005250}
5251
5252/* Append data in the output side of the buffer. This data is immediately
5253 * sent. The function returns the amount of data written. If the buffer
5254 * cannot contain the data, the function yields. The function returns -1
5255 * if the channel is closed.
5256 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005257__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005258{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005259 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005260 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005261 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005262 struct htx *htx = htx_from_buf(&res->buf);
5263 const char *data;
5264 size_t len;
5265 int l = MAY_LJMP(luaL_checkinteger(L, 3));
5266 int max;
5267
Christopher Faulet9060fc02019-07-03 11:39:30 +02005268 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005269 if (!max)
5270 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005271
5272 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
5273
5274 /* Get the max amount of data which can write as input in the channel. */
5275 if (max > (len - l))
5276 max = len - l;
5277
5278 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02005279 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005280 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005281
5282 /* update counters. */
5283 l += max;
5284 lua_pop(L, 1);
5285 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005286
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005287 /* If some data is not send, declares the situation to the
5288 * applet, and returns a yield.
5289 */
5290 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005291 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005292 htx_to_buf(htx, &res->buf);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005293 sc_need_room(sc);
Willy Tarreau9635e032018-10-16 17:52:55 +02005294 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005295 }
5296
Christopher Fauleta2097962019-07-15 16:25:33 +02005297 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005298 return 1;
5299}
5300
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005301/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005302 * yield the LUA process, and resume it without checking the
5303 * input arguments.
5304 */
5305__LJMP static int hlua_applet_http_send(lua_State *L)
5306{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005307 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005308 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005309
5310 /* We want to send some data. Headers must be sent. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005311 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005312 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
5313 WILL_LJMP(lua_error(L));
5314 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005315
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005316 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02005317 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005318
Christopher Fauleta2097962019-07-15 16:25:33 +02005319 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005320}
5321
5322__LJMP static int hlua_applet_http_addheader(lua_State *L)
5323{
5324 const char *name;
5325 int ret;
5326
5327 MAY_LJMP(hlua_checkapplet_http(L, 1));
5328 name = MAY_LJMP(luaL_checkstring(L, 2));
5329 MAY_LJMP(luaL_checkstring(L, 3));
5330
5331 /* Push in the stack the "response" entry. */
5332 ret = lua_getfield(L, 1, "response");
5333 if (ret != LUA_TTABLE) {
5334 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
5335 "is expected as an array. %s found", lua_typename(L, ret));
5336 WILL_LJMP(lua_error(L));
5337 }
5338
5339 /* check if the header is already registered if it is not
5340 * the case, register it.
5341 */
5342 ret = lua_getfield(L, -1, name);
5343 if (ret == LUA_TNIL) {
5344
5345 /* Entry not found. */
5346 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
5347
5348 /* Insert the new header name in the array in the top of the stack.
5349 * It left the new array in the top of the stack.
5350 */
5351 lua_newtable(L);
5352 lua_pushvalue(L, 2);
5353 lua_pushvalue(L, -2);
5354 lua_settable(L, -4);
5355
5356 } else if (ret != LUA_TTABLE) {
5357
5358 /* corruption error. */
5359 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
5360 "is expected as an array. %s found", name, lua_typename(L, ret));
5361 WILL_LJMP(lua_error(L));
5362 }
5363
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005364 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005365 * the header value as new entry.
5366 */
5367 lua_pushvalue(L, 3);
5368 ret = lua_rawlen(L, -2);
5369 lua_rawseti(L, -2, ret + 1);
5370 lua_pushboolean(L, 1);
5371 return 1;
5372}
5373
5374__LJMP static int hlua_applet_http_status(lua_State *L)
5375{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005376 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005377 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005378 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005379 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005380
5381 if (status < 100 || status > 599) {
5382 lua_pushboolean(L, 0);
5383 return 1;
5384 }
5385
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005386 http_ctx->status = status;
5387 http_ctx->reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005388 lua_pushboolean(L, 1);
5389 return 1;
5390}
5391
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005392
Christopher Fauleta2097962019-07-15 16:25:33 +02005393__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005394{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005395 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005396 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02005397 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005398 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005399 struct htx *htx;
5400 struct htx_sl *sl;
5401 struct h1m h1m;
5402 const char *status, *reason;
5403 const char *name, *value;
5404 size_t nlen, vlen;
5405 unsigned int flags;
5406
5407 /* Send the message at once. */
5408 htx = htx_from_buf(&res->buf);
5409 h1m_init_res(&h1m);
5410
5411 /* Use the same http version than the request. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005412 status = ultoa_r(http_ctx->status, trash.area, trash.size);
5413 reason = http_ctx->reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005414 if (reason == NULL)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005415 reason = http_get_reason(http_ctx->status);
5416 if (http_ctx->flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005417 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5418 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
5419 }
5420 else {
5421 flags = HTX_SL_F_IS_RESP;
5422 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
5423 }
5424 if (!sl) {
5425 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005426 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005427 WILL_LJMP(lua_error(L));
5428 }
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005429 sl->info.res.status = http_ctx->status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005430
5431 /* Get the array associated to the field "response" in the object AppletHTTP. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005432 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
5433 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005434 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005435 WILL_LJMP(lua_error(L));
5436 }
5437
5438 /* Browse the list of headers. */
5439 lua_pushnil(L);
5440 while(lua_next(L, -2) != 0) {
5441 /* We expect a string as -2. */
5442 if (lua_type(L, -2) != LUA_TSTRING) {
5443 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005444 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005445 lua_typename(L, lua_type(L, -2)));
5446 WILL_LJMP(lua_error(L));
5447 }
5448 name = lua_tolstring(L, -2, &nlen);
5449
5450 /* We expect an array as -1. */
5451 if (lua_type(L, -1) != LUA_TTABLE) {
5452 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 +02005453 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005454 name,
5455 lua_typename(L, lua_type(L, -1)));
5456 WILL_LJMP(lua_error(L));
5457 }
5458
5459 /* Browse the table who is on the top of the stack. */
5460 lua_pushnil(L);
5461 while(lua_next(L, -2) != 0) {
5462 int id;
5463
5464 /* We expect a number as -2. */
5465 if (lua_type(L, -2) != LUA_TNUMBER) {
5466 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 +02005467 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005468 name,
5469 lua_typename(L, lua_type(L, -2)));
5470 WILL_LJMP(lua_error(L));
5471 }
5472 id = lua_tointeger(L, -2);
5473
5474 /* We expect a string as -2. */
5475 if (lua_type(L, -1) != LUA_TSTRING) {
5476 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 +02005477 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005478 name, id,
5479 lua_typename(L, lua_type(L, -1)));
5480 WILL_LJMP(lua_error(L));
5481 }
5482 value = lua_tolstring(L, -1, &vlen);
5483
5484 /* Simple Protocol checks. */
Christopher Faulet545fbba2021-09-28 09:36:25 +02005485 if (isteqi(ist2(name, nlen), ist("transfer-encoding"))) {
5486 int ret;
5487
5488 ret = h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
5489 if (ret < 0) {
5490 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
5491 luactx->appctx->rule->arg.hlua_rule->fcn->name,
5492 name);
5493 WILL_LJMP(lua_error(L));
5494 }
5495 else if (ret == 0)
5496 goto next; /* Skip it */
5497 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005498 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
5499 struct ist v = ist2(value, vlen);
5500 int ret;
5501
5502 ret = h1_parse_cont_len_header(&h1m, &v);
5503 if (ret < 0) {
5504 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005505 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005506 name);
5507 WILL_LJMP(lua_error(L));
5508 }
5509 else if (ret == 0)
5510 goto next; /* Skip it */
5511 }
5512
5513 /* Add a new header */
5514 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
5515 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005516 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005517 name);
5518 WILL_LJMP(lua_error(L));
5519 }
5520 next:
5521 /* Remove the array from the stack, and get next element with a remaining string. */
5522 lua_pop(L, 1);
5523 }
5524
5525 /* Remove the array from the stack, and get next element with a remaining string. */
5526 lua_pop(L, 1);
5527 }
5528
5529 if (h1m.flags & H1_MF_CHNK)
5530 h1m.flags &= ~H1_MF_CLEN;
5531 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5532 h1m.flags |= H1_MF_XFER_LEN;
5533
5534 /* Uset HTX start-line flags */
5535 if (h1m.flags & H1_MF_XFER_ENC)
5536 flags |= HTX_SL_F_XFER_ENC;
5537 if (h1m.flags & H1_MF_XFER_LEN) {
5538 flags |= HTX_SL_F_XFER_LEN;
5539 if (h1m.flags & H1_MF_CHNK)
5540 flags |= HTX_SL_F_CHNK;
5541 else if (h1m.flags & H1_MF_CLEN)
5542 flags |= HTX_SL_F_CLEN;
5543 if (h1m.body_len == 0)
5544 flags |= HTX_SL_F_BODYLESS;
5545 }
5546 sl->flags |= flags;
5547
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005548 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005549 * and the status code implies the presence of a message body, we must
5550 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005551 * for the keepalive compliance. If the applet announces a transfer-encoding
5552 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005553 */
5554 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005555 http_ctx->status >= 200 && http_ctx->status != 204 && http_ctx->status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005556 /* Add a new header */
5557 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
5558 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
5559 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005560 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005561 WILL_LJMP(lua_error(L));
5562 }
5563 }
5564
5565 /* Finalize headers. */
5566 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
5567 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005568 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005569 WILL_LJMP(lua_error(L));
5570 }
5571
5572 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
5573 b_reset(&res->buf);
5574 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
5575 WILL_LJMP(lua_error(L));
5576 }
5577
5578 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005579 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005580
5581 /* Headers sent, set the flag. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005582 http_ctx->flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005583 return 0;
5584
5585}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005586/* We will build the status line and the headers of the HTTP response.
5587 * We will try send at once if its not possible, we give back the hand
5588 * waiting for more room.
5589 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005590__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005591{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005592 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005593 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005594 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005595
5596 if (co_data(res)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02005597 sc_need_room(sc);
Christopher Fauleta2097962019-07-15 16:25:33 +02005598 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005599 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005600 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005601}
5602
5603
Christopher Fauleta2097962019-07-15 16:25:33 +02005604__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005605{
Christopher Fauleta2097962019-07-15 16:25:33 +02005606 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005607}
5608
Christopher Fauleta2097962019-07-15 16:25:33 +02005609/*
5610 *
5611 *
5612 * Class HTTP
5613 *
5614 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005615 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005616
5617/* Returns a struct hlua_txn if the stack entry "ud" is
5618 * a class stream, otherwise it throws an error.
5619 */
5620__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005621{
Christopher Fauleta2097962019-07-15 16:25:33 +02005622 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
5623}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005624
Christopher Fauleta2097962019-07-15 16:25:33 +02005625/* This function creates and push in the stack a HTTP object
5626 * according with a current TXN.
5627 */
5628static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
5629{
5630 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005631
Christopher Fauleta2097962019-07-15 16:25:33 +02005632 /* Check stack size. */
5633 if (!lua_checkstack(L, 3))
5634 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005635
Christopher Fauleta2097962019-07-15 16:25:33 +02005636 /* Create the object: obj[0] = userdata.
5637 * Note that the base of the Converters object is the
5638 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005639 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005640 lua_newtable(L);
5641 htxn = lua_newuserdata(L, sizeof(*htxn));
5642 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005643
5644 htxn->s = txn->s;
5645 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02005646 htxn->dir = txn->dir;
5647 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005648
5649 /* Pop a class stream metatable and affect it to the table. */
5650 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
5651 lua_setmetatable(L, -2);
5652
5653 return 1;
5654}
5655
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005656/* This function creates and returns an array containing the status-line
5657 * elements. This function does not fails.
5658 */
5659__LJMP static int hlua_http_get_stline(lua_State *L, struct htx_sl *sl)
5660{
5661 /* Create the table. */
5662 lua_newtable(L);
5663
5664 if (sl->flags & HTX_SL_F_IS_RESP) {
5665 lua_pushstring(L, "version");
5666 lua_pushlstring(L, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl));
5667 lua_settable(L, -3);
5668 lua_pushstring(L, "code");
5669 lua_pushlstring(L, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl));
5670 lua_settable(L, -3);
5671 lua_pushstring(L, "reason");
5672 lua_pushlstring(L, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl));
5673 lua_settable(L, -3);
5674 }
5675 else {
5676 lua_pushstring(L, "method");
5677 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
5678 lua_settable(L, -3);
5679 lua_pushstring(L, "uri");
5680 lua_pushlstring(L, HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl));
5681 lua_settable(L, -3);
5682 lua_pushstring(L, "version");
5683 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
5684 lua_settable(L, -3);
5685 }
5686 return 1;
5687}
5688
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005689/* This function creates ans returns an array of HTTP headers.
5690 * This function does not fails. It is used as wrapper with the
5691 * 2 following functions.
5692 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005693__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005694{
Christopher Fauleta2097962019-07-15 16:25:33 +02005695 struct htx *htx;
5696 int32_t pos;
5697
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005698 /* Create the table. */
5699 lua_newtable(L);
5700
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005701
Christopher Fauleta2097962019-07-15 16:25:33 +02005702 htx = htxbuf(&msg->chn->buf);
5703 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
5704 struct htx_blk *blk = htx_get_blk(htx, pos);
5705 enum htx_blk_type type = htx_get_blk_type(blk);
5706 struct ist n, v;
5707 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005708
Christopher Fauleta2097962019-07-15 16:25:33 +02005709 if (type == HTX_BLK_HDR) {
5710 n = htx_get_blk_name(htx,blk);
5711 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005712 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005713 else if (type == HTX_BLK_EOH)
5714 break;
5715 else
5716 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005717
Christopher Fauleta2097962019-07-15 16:25:33 +02005718 /* Check for existing entry:
5719 * assume that the table is on the top of the stack, and
5720 * push the key in the stack, the function lua_gettable()
5721 * perform the lookup.
5722 */
5723 lua_pushlstring(L, n.ptr, n.len);
5724 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005725
Christopher Fauleta2097962019-07-15 16:25:33 +02005726 switch (lua_type(L, -1)) {
5727 case LUA_TNIL:
5728 /* Table not found, create it. */
5729 lua_pop(L, 1); /* remove the nil value. */
5730 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
5731 lua_newtable(L); /* create and push empty table. */
5732 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5733 lua_rawseti(L, -2, 0); /* index header value (pop it). */
5734 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01005735 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005736
Christopher Fauleta2097962019-07-15 16:25:33 +02005737 case LUA_TTABLE:
5738 /* Entry found: push the value in the table. */
5739 len = lua_rawlen(L, -1);
5740 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5741 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
5742 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
5743 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005744
Christopher Fauleta2097962019-07-15 16:25:33 +02005745 default:
5746 /* Other cases are errors. */
5747 hlua_pusherror(L, "internal error during the parsing of headers.");
5748 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005749 }
5750 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005751 return 1;
5752}
5753
5754__LJMP static int hlua_http_req_get_headers(lua_State *L)
5755{
5756 struct hlua_txn *htxn;
5757
5758 MAY_LJMP(check_args(L, 1, "req_get_headers"));
5759 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5760
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005761 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005762 WILL_LJMP(lua_error(L));
5763
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005764 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005765}
5766
5767__LJMP static int hlua_http_res_get_headers(lua_State *L)
5768{
5769 struct hlua_txn *htxn;
5770
5771 MAY_LJMP(check_args(L, 1, "res_get_headers"));
5772 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5773
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005774 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005775 WILL_LJMP(lua_error(L));
5776
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005777 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005778}
5779
5780/* This function replace full header, or just a value in
5781 * the request or in the response. It is a wrapper fir the
5782 * 4 following functions.
5783 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005784__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005785{
5786 size_t name_len;
5787 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5788 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
5789 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02005790 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02005791 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005792
Dragan Dosen26743032019-04-30 15:54:36 +02005793 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005794 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
5795
Christopher Fauleta2097962019-07-15 16:25:33 +02005796 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005797 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02005798 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005799 return 0;
5800}
5801
5802__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
5803{
5804 struct hlua_txn *htxn;
5805
5806 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5807 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5808
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005809 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005810 WILL_LJMP(lua_error(L));
5811
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005812 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005813}
5814
5815__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
5816{
5817 struct hlua_txn *htxn;
5818
5819 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
5820 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5821
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005822 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005823 WILL_LJMP(lua_error(L));
5824
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005825 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005826}
5827
5828__LJMP static int hlua_http_req_rep_val(lua_State *L)
5829{
5830 struct hlua_txn *htxn;
5831
5832 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5833 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5834
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005835 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005836 WILL_LJMP(lua_error(L));
5837
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005838 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005839}
5840
5841__LJMP static int hlua_http_res_rep_val(lua_State *L)
5842{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005843 struct hlua_txn *htxn;
5844
5845 MAY_LJMP(check_args(L, 4, "res_rep_val"));
5846 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5847
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005848 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005849 WILL_LJMP(lua_error(L));
5850
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005851 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005852}
5853
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005854/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005855 * It is a wrapper for the 2 following functions.
5856 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005857__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005858{
5859 size_t len;
5860 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005861 struct htx *htx = htxbuf(&msg->chn->buf);
5862 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005863
Christopher Fauleta2097962019-07-15 16:25:33 +02005864 ctx.blk = NULL;
5865 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5866 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005867 return 0;
5868}
5869
5870__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5871{
5872 struct hlua_txn *htxn;
5873
5874 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5875 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5876
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005877 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005878 WILL_LJMP(lua_error(L));
5879
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005880 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005881}
5882
5883__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5884{
5885 struct hlua_txn *htxn;
5886
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005887 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005888 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5889
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005890 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005891 WILL_LJMP(lua_error(L));
5892
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005893 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005894}
5895
5896/* This function adds an header. It is a wrapper used by
5897 * the 2 following functions.
5898 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005899__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005900{
5901 size_t name_len;
5902 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5903 size_t value_len;
5904 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005905 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005906
Christopher Fauleta2097962019-07-15 16:25:33 +02005907 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5908 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005909 return 0;
5910}
5911
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005912__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5913{
5914 struct hlua_txn *htxn;
5915
5916 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5917 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5918
5919 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5920 WILL_LJMP(lua_error(L));
5921
5922 return hlua_http_add_hdr(L, &htxn->s->txn->req);
5923}
5924
5925__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5926{
5927 struct hlua_txn *htxn;
5928
5929 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5930 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5931
5932 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
5933 WILL_LJMP(lua_error(L));
5934
5935 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
5936}
5937
5938static int hlua_http_req_set_hdr(lua_State *L)
5939{
5940 struct hlua_txn *htxn;
5941
5942 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5943 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5944
5945 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5946 WILL_LJMP(lua_error(L));
5947
5948 hlua_http_del_hdr(L, &htxn->s->txn->req);
5949 return hlua_http_add_hdr(L, &htxn->s->txn->req);
5950}
5951
5952static int hlua_http_res_set_hdr(lua_State *L)
5953{
5954 struct hlua_txn *htxn;
5955
5956 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
5957 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5958
5959 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
5960 WILL_LJMP(lua_error(L));
5961
5962 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
5963 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
5964}
5965
5966/* This function set the method. */
5967static int hlua_http_req_set_meth(lua_State *L)
5968{
5969 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5970 size_t name_len;
5971 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5972
5973 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5974 WILL_LJMP(lua_error(L));
5975
5976 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
5977 return 1;
5978}
5979
5980/* This function set the method. */
5981static int hlua_http_req_set_path(lua_State *L)
5982{
5983 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5984 size_t name_len;
5985 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5986
5987 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5988 WILL_LJMP(lua_error(L));
5989
5990 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
5991 return 1;
5992}
5993
5994/* This function set the query-string. */
5995static int hlua_http_req_set_query(lua_State *L)
5996{
5997 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5998 size_t name_len;
5999 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6000
6001 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6002 WILL_LJMP(lua_error(L));
6003
6004 /* Check length. */
6005 if (name_len > trash.size - 1) {
6006 lua_pushboolean(L, 0);
6007 return 1;
6008 }
6009
6010 /* Add the mark question as prefix. */
6011 chunk_reset(&trash);
6012 trash.area[trash.data++] = '?';
6013 memcpy(trash.area + trash.data, name, name_len);
6014 trash.data += name_len;
6015
6016 lua_pushboolean(L,
6017 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
6018 return 1;
6019}
6020
6021/* This function set the uri. */
6022static int hlua_http_req_set_uri(lua_State *L)
6023{
6024 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6025 size_t name_len;
6026 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6027
6028 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6029 WILL_LJMP(lua_error(L));
6030
6031 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
6032 return 1;
6033}
6034
6035/* This function set the response code & optionally reason. */
6036static int hlua_http_res_set_status(lua_State *L)
6037{
6038 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6039 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
6040 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6041 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
6042
6043 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6044 WILL_LJMP(lua_error(L));
6045
6046 http_res_set_status(code, reason, htxn->s);
6047 return 0;
6048}
6049
6050/*
6051 *
6052 *
6053 * Class HTTPMessage
6054 *
6055 *
6056 */
6057
6058/* Returns a struct http_msg if the stack entry "ud" is a class HTTPMessage,
6059 * otherwise it throws an error.
6060 */
6061__LJMP static struct http_msg *hlua_checkhttpmsg(lua_State *L, int ud)
6062{
6063 return MAY_LJMP(hlua_checkudata(L, ud, class_http_msg_ref));
6064}
6065
6066/* Creates and pushes on the stack a HTTP object according with a current TXN.
6067 */
Christopher Faulet78c35472020-02-26 17:14:08 +01006068static int hlua_http_msg_new(lua_State *L, struct http_msg *msg)
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006069{
6070 /* Check stack size. */
6071 if (!lua_checkstack(L, 3))
6072 return 0;
6073
6074 lua_newtable(L);
6075 lua_pushlightuserdata(L, msg);
6076 lua_rawseti(L, -2, 0);
6077
6078 /* Create the "channel" field that contains the request channel object. */
6079 lua_pushstring(L, "channel");
6080 if (!hlua_channel_new(L, msg->chn))
6081 return 0;
6082 lua_rawset(L, -3);
6083
6084 /* Pop a class stream metatable and affect it to the table. */
6085 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_msg_ref);
6086 lua_setmetatable(L, -2);
6087
6088 return 1;
6089}
6090
6091/* Helper function returning a filter attached to the HTTP message at the
6092 * position <ud> in the stack, filling the current offset and length of the
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006093 * filter. If no filter is attached, NULL is returned and <offset> and <len> are
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006094 * filled with output and input length respectively.
6095 */
6096static struct filter *hlua_http_msg_filter(lua_State *L, int ud, struct http_msg *msg, size_t *offset, size_t *len)
6097{
6098 struct channel *chn = msg->chn;
6099 struct htx *htx = htxbuf(&chn->buf);
6100 struct filter *filter = NULL;
6101
6102 *offset = co_data(msg->chn);
6103 *len = htx->data - co_data(msg->chn);
6104
6105 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
6106 filter = lua_touserdata (L, -1);
6107 if (msg->msg_state >= HTTP_MSG_DATA) {
6108 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6109
6110 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
6111 *len = flt_ctx->cur_len[CHN_IDX(chn)];
6112 }
6113 }
6114
6115 lua_pop(L, 1);
6116 return filter;
6117}
6118
6119/* Returns true if the channel attached to the HTTP message is the response
6120 * channel.
6121 */
6122__LJMP static int hlua_http_msg_is_resp(lua_State *L)
6123{
6124 struct http_msg *msg;
6125
6126 MAY_LJMP(check_args(L, 1, "is_resp"));
6127 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6128
6129 lua_pushboolean(L, !!(msg->chn->flags & CF_ISRESP));
6130 return 1;
6131}
6132
6133/* Returns an array containing the elements status-line of the HTTP message. It relies
6134 * on hlua_http_get_stline().
6135 */
6136__LJMP static int hlua_http_msg_get_stline(lua_State *L)
6137{
6138 struct http_msg *msg;
6139 struct htx *htx;
6140 struct htx_sl *sl;
6141
6142 MAY_LJMP(check_args(L, 1, "get_stline"));
6143 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6144
6145 if (msg->msg_state > HTTP_MSG_BODY)
6146 WILL_LJMP(lua_error(L));
6147
6148 htx = htxbuf(&msg->chn->buf);
6149 sl = http_get_stline(htx);
6150 if (!sl)
6151 return 0;
6152 return hlua_http_get_stline(L, sl);
6153}
6154
6155/* Returns an array containing all headers of the HTTP message. it relies on
6156 * hlua_http_get_headers().
6157 */
6158__LJMP static int hlua_http_msg_get_headers(lua_State *L)
6159{
6160 struct http_msg *msg;
6161
6162 MAY_LJMP(check_args(L, 1, "get_headers"));
6163 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6164
6165 if (msg->msg_state > HTTP_MSG_BODY)
6166 WILL_LJMP(lua_error(L));
6167
6168 return hlua_http_get_headers(L, msg);
6169}
6170
6171/* Deletes all occurrences of an header in the HTTP message matching on its
6172 * name. It relies on hlua_http_del_hdr().
6173 */
6174__LJMP static int hlua_http_msg_del_hdr(lua_State *L)
6175{
6176 struct http_msg *msg;
6177
6178 MAY_LJMP(check_args(L, 2, "del_header"));
6179 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6180
6181 if (msg->msg_state > HTTP_MSG_BODY)
6182 WILL_LJMP(lua_error(L));
6183
6184 return hlua_http_del_hdr(L, msg);
6185}
6186
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006187/* Matches the full value line of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006188 * message given its name against a regex and replaces it if it matches. It
6189 * relies on hlua_http_rep_hdr().
6190 */
6191__LJMP static int hlua_http_msg_rep_hdr(lua_State *L)
6192{
6193 struct http_msg *msg;
6194
6195 MAY_LJMP(check_args(L, 4, "rep_header"));
6196 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6197
6198 if (msg->msg_state > HTTP_MSG_BODY)
6199 WILL_LJMP(lua_error(L));
6200
6201 return hlua_http_rep_hdr(L, msg, 1);
6202}
6203
Ilya Shipitsinbd6b4be2021-10-15 16:18:21 +05006204/* Matches all comma-separated values of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006205 * message given its name against a regex and replaces it if it matches. It
6206 * relies on hlua_http_rep_hdr().
6207 */
6208__LJMP static int hlua_http_msg_rep_val(lua_State *L)
6209{
6210 struct http_msg *msg;
6211
6212 MAY_LJMP(check_args(L, 4, "rep_value"));
6213 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6214
6215 if (msg->msg_state > HTTP_MSG_BODY)
6216 WILL_LJMP(lua_error(L));
6217
6218 return hlua_http_rep_hdr(L, msg, 0);
6219}
6220
6221/* Add an header in the HTTP message. It relies on hlua_http_add_hdr() */
6222__LJMP static int hlua_http_msg_add_hdr(lua_State *L)
6223{
6224 struct http_msg *msg;
6225
6226 MAY_LJMP(check_args(L, 3, "add_header"));
6227 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6228
6229 if (msg->msg_state > HTTP_MSG_BODY)
6230 WILL_LJMP(lua_error(L));
6231
6232 return hlua_http_add_hdr(L, msg);
6233}
6234
6235/* Add an header in the HTTP message removing existing headers with the same
6236 * name. It relies on hlua_http_del_hdr() and hlua_http_add_hdr().
6237 */
6238__LJMP static int hlua_http_msg_set_hdr(lua_State *L)
6239{
6240 struct http_msg *msg;
6241
6242 MAY_LJMP(check_args(L, 3, "set_header"));
6243 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6244
6245 if (msg->msg_state > HTTP_MSG_BODY)
6246 WILL_LJMP(lua_error(L));
6247
6248 hlua_http_del_hdr(L, msg);
6249 return hlua_http_add_hdr(L, msg);
6250}
6251
6252/* Rewrites the request method. It relies on http_req_replace_stline(). */
6253__LJMP static int hlua_http_msg_set_meth(lua_State *L)
6254{
6255 struct stream *s;
6256 struct http_msg *msg;
6257 const char *name;
6258 size_t name_len;
6259
6260 MAY_LJMP(check_args(L, 2, "set_method"));
6261 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6262 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6263
6264 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6265 WILL_LJMP(lua_error(L));
6266
6267 s = chn_strm(msg->chn);
6268 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, s->be, s) != -1);
6269 return 1;
6270}
6271
6272/* Rewrites the request path. It relies on http_req_replace_stline(). */
6273__LJMP static int hlua_http_msg_set_path(lua_State *L)
6274{
6275 struct stream *s;
6276 struct http_msg *msg;
6277 const char *name;
6278 size_t name_len;
6279
6280 MAY_LJMP(check_args(L, 2, "set_path"));
6281 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6282 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6283
6284 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6285 WILL_LJMP(lua_error(L));
6286
6287 s = chn_strm(msg->chn);
6288 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, s->be, s) != -1);
6289 return 1;
6290}
6291
6292/* Rewrites the request query-string. It relies on http_req_replace_stline(). */
6293__LJMP static int hlua_http_msg_set_query(lua_State *L)
6294{
6295 struct stream *s;
6296 struct http_msg *msg;
6297 const char *name;
6298 size_t name_len;
6299
6300 MAY_LJMP(check_args(L, 2, "set_query"));
6301 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6302 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6303
6304 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6305 WILL_LJMP(lua_error(L));
6306
6307 /* Check length. */
6308 if (name_len > trash.size - 1) {
6309 lua_pushboolean(L, 0);
6310 return 1;
6311 }
6312
6313 /* Add the mark question as prefix. */
6314 chunk_reset(&trash);
6315 trash.area[trash.data++] = '?';
6316 memcpy(trash.area + trash.data, name, name_len);
6317 trash.data += name_len;
6318
6319 s = chn_strm(msg->chn);
6320 lua_pushboolean(L, http_req_replace_stline(2, trash.area, trash.data, s->be, s) != -1);
6321 return 1;
6322}
6323
6324/* Rewrites the request URI. It relies on http_req_replace_stline(). */
6325__LJMP static int hlua_http_msg_set_uri(lua_State *L)
6326{
6327 struct stream *s;
6328 struct http_msg *msg;
6329 const char *name;
6330 size_t name_len;
6331
6332 MAY_LJMP(check_args(L, 2, "set_uri"));
6333 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6334 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6335
6336 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6337 WILL_LJMP(lua_error(L));
6338
6339 s = chn_strm(msg->chn);
6340 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, s->be, s) != -1);
6341 return 1;
6342}
6343
6344/* Rewrites the response status code. It relies on http_res_set_status(). */
6345__LJMP static int hlua_http_msg_set_status(lua_State *L)
6346{
6347 struct http_msg *msg;
6348 unsigned int code;
6349 const char *reason;
6350 size_t reason_len;
6351
6352 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6353 code = MAY_LJMP(luaL_checkinteger(L, 2));
6354 reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, &reason_len));
6355
6356 if (!(msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6357 WILL_LJMP(lua_error(L));
6358
6359 lua_pushboolean(L, http_res_set_status(code, ist2(reason, reason_len), chn_strm(msg->chn)) != -1);
6360 return 1;
6361}
6362
6363/* Returns true if the HTTP message is full. */
6364__LJMP static int hlua_http_msg_is_full(lua_State *L)
6365{
6366 struct http_msg *msg;
6367
6368 MAY_LJMP(check_args(L, 1, "is_full"));
6369 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6370 lua_pushboolean(L, channel_full(msg->chn, 0));
6371 return 1;
6372}
6373
6374/* Returns true if the HTTP message may still receive data. */
6375__LJMP static int hlua_http_msg_may_recv(lua_State *L)
6376{
6377 struct http_msg *msg;
6378 struct htx *htx;
6379
6380 MAY_LJMP(check_args(L, 1, "may_recv"));
6381 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6382 htx = htxbuf(&msg->chn->buf);
6383 lua_pushboolean(L, (htx_expect_more(htx) && !channel_input_closed(msg->chn) && channel_may_recv(msg->chn)));
6384 return 1;
6385}
6386
6387/* Returns true if the HTTP message EOM was received */
6388__LJMP static int hlua_http_msg_is_eom(lua_State *L)
6389{
6390 struct http_msg *msg;
6391 struct htx *htx;
6392
6393 MAY_LJMP(check_args(L, 1, "may_recv"));
6394 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6395 htx = htxbuf(&msg->chn->buf);
6396 lua_pushboolean(L, !htx_expect_more(htx));
6397 return 1;
6398}
6399
6400/* Returns the number of bytes available in the input side of the HTTP
6401 * message. This function never fails.
6402 */
6403__LJMP static int hlua_http_msg_get_in_len(lua_State *L)
6404{
6405 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006406 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006407
6408 MAY_LJMP(check_args(L, 1, "input"));
6409 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006410 hlua_http_msg_filter(L, 1, msg, &output, &input);
6411 lua_pushinteger(L, input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006412 return 1;
6413}
6414
6415/* Returns the number of bytes available in the output side of the HTTP
6416 * message. This function never fails.
6417 */
6418__LJMP static int hlua_http_msg_get_out_len(lua_State *L)
6419{
6420 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006421 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006422
6423 MAY_LJMP(check_args(L, 1, "output"));
6424 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006425 hlua_http_msg_filter(L, 1, msg, &output, &input);
6426 lua_pushinteger(L, output);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006427 return 1;
6428}
6429
6430/* Copies at most <len> bytes of DATA blocks from the HTTP message <msg>
6431 * starting at the offset <offset> and put it in a string LUA variables. It
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006432 * returns the built string length. It stops on the first non-DATA HTX
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006433 * block. This function is called during the payload filtering, so the headers
6434 * are already scheduled for output (from the filter point of view).
6435 */
6436static int _hlua_http_msg_dup(struct http_msg *msg, lua_State *L, size_t offset, size_t len)
6437{
6438 struct htx *htx = htxbuf(&msg->chn->buf);
6439 struct htx_blk *blk;
6440 struct htx_ret htxret;
6441 luaL_Buffer b;
6442 int ret = 0;
6443
6444 luaL_buffinit(L, &b);
6445 htxret = htx_find_offset(htx, offset);
6446 for (blk = htxret.blk, offset = htxret.ret; blk && len; blk = htx_get_next_blk(htx, blk)) {
6447 enum htx_blk_type type = htx_get_blk_type(blk);
6448 struct ist v;
6449
6450 switch (type) {
6451 case HTX_BLK_UNUSED:
6452 break;
6453
6454 case HTX_BLK_DATA:
6455 v = htx_get_blk_value(htx, blk);
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006456 v = istadv(v, offset);
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006457 v = isttrim(v, len);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006458
6459 luaL_addlstring(&b, v.ptr, v.len);
6460 ret += v.len;
6461 break;
6462
6463 default:
vishnu0af4bd72021-10-24 06:46:24 +05306464 if (!ret)
6465 goto no_data;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006466 goto end;
6467 }
6468 offset = 0;
6469 }
6470
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006471end:
vishnu0af4bd72021-10-24 06:46:24 +05306472 if (!ret && (htx->flags & HTX_FL_EOM))
6473 goto no_data;
6474 luaL_pushresult(&b);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006475 return ret;
vishnu0af4bd72021-10-24 06:46:24 +05306476
6477 no_data:
6478 /* Remove the empty string and push nil on the stack */
6479 lua_pop(L, 1);
6480 lua_pushnil(L);
6481 return 0;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006482}
6483
6484/* Copies the string <str> to the HTTP message <msg> at the offset
6485 * <offset>. This function returns -1 if data cannot be copied. Otherwise, it
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006486 * returns the amount of data written. This function is responsible to update
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006487 * the filter context.
6488 */
6489static int _hlua_http_msg_insert(struct http_msg *msg, struct filter *filter, struct ist str, size_t offset)
6490{
6491 struct htx *htx = htx_from_buf(&msg->chn->buf);
6492 struct htx_ret htxret;
6493 int /*max, */ret = 0;
6494
6495 /* Nothing to do, just return */
6496 if (unlikely(istlen(str) == 0))
6497 goto end;
6498
6499 if (istlen(str) > htx_free_data_space(htx)) {
6500 ret = -1;
6501 goto end;
6502 }
6503
6504 htxret = htx_find_offset(htx, offset);
6505 if (!htxret.blk || htx_get_blk_type(htxret.blk) != HTX_BLK_DATA) {
6506 if (!htx_add_last_data(htx, str))
6507 goto end;
6508 }
6509 else {
6510 struct ist v = htx_get_blk_value(htx, htxret.blk);
6511 v.ptr += htxret.ret;
6512 v.len = 0;
6513 if (!htx_replace_blk_value(htx, htxret.blk, v, str))
6514 goto end;
6515 }
6516 ret = str.len;
6517 if (ret) {
6518 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6519 flt_update_offsets(filter, msg->chn, ret);
6520 flt_ctx->cur_len[CHN_IDX(msg->chn)] += ret;
6521 }
6522
6523 end:
6524 htx_to_buf(htx, &msg->chn->buf);
6525 return ret;
6526}
6527
6528/* Helper function removing at most <len> bytes of DATA blocks at the absolute
6529 * position <offset>. It stops on the first non-DATA HTX block. This function is
6530 * called during the payload filtering, so the headers are already scheduled for
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006531 * output (from the filter point of view). This function is responsible to
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006532 * update the filter context.
6533 */
6534static void _hlua_http_msg_delete(struct http_msg *msg, struct filter *filter, size_t offset, size_t len)
6535{
6536 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6537 struct htx *htx = htx_from_buf(&msg->chn->buf);
6538 struct htx_blk *blk;
6539 struct htx_ret htxret;
6540 size_t ret = 0;
6541
6542 /* Be sure <len> is always the amount of DATA to remove */
6543 if (htx->data == offset+len && htx_get_tail_type(htx) == HTX_BLK_DATA) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006544 /* When htx tail type == HTX_BLK_DATA, no need to take care
6545 * of special blocks like HTX_BLK_EOT.
6546 * We simply truncate after offset
6547 * (truncate targeted blk and discard the following ones)
6548 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006549 htx_truncate(htx, offset);
6550 ret = len;
6551 goto end;
6552 }
6553
6554 htxret = htx_find_offset(htx, offset);
6555 blk = htxret.blk;
6556 if (htxret.ret) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006557 /* dealing with offset: we need to trim targeted blk */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006558 struct ist v;
6559
6560 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
6561 goto end;
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006562
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006563 v = htx_get_blk_value(htx, blk);
Tim Duesterhusa029d782022-10-08 12:33:18 +02006564 v = istadv(v, htxret.ret);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006565
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006566 v = isttrim(v, len);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006567 /* trimming data in blk: discard everything after the offset
6568 * (replace 'v' with 'IST_NULL')
6569 */
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006570 blk = htx_replace_blk_value(htx, blk, v, IST_NULL);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006571 if (blk && v.len < len) {
6572 /* In this case, caller wants to keep removing data,
6573 * but we need to spare current blk
6574 * because it was already trimmed
6575 */
6576 blk = htx_get_next_blk(htx, blk);
6577 }
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006578 len -= v.len;
6579 ret += v.len;
6580 }
6581
6582
6583 while (blk && len) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006584 /* there is more data that needs to be discarded */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006585 enum htx_blk_type type = htx_get_blk_type(blk);
6586 uint32_t sz = htx_get_blksz(blk);
6587
6588 switch (type) {
6589 case HTX_BLK_UNUSED:
6590 break;
6591
6592 case HTX_BLK_DATA:
6593 if (len < sz) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006594 /* don't discard whole blk, only part of it
6595 * (from the beginning)
6596 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006597 htx_cut_data_blk(htx, blk, len);
6598 ret += len;
6599 goto end;
6600 }
6601 break;
6602
6603 default:
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006604 /* HTX_BLK_EOT blk won't be removed */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006605 goto end;
6606 }
6607
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006608 /* Remove all the data block */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006609 len -= sz;
6610 ret += sz;
6611 blk = htx_remove_blk(htx, blk);
6612 }
6613
6614end:
6615 flt_update_offsets(filter, msg->chn, -ret);
6616 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
6617 /* WARNING: we don't call htx_to_buf() on purpose, because we don't want
6618 * to loose the EOM flag if the message is empty.
6619 */
6620}
6621
6622/* Copies input data found in an HTTP message. Unlike the channel function used
6623 * to duplicate raw data, this one can only be called inside a filter, from
6624 * http_payload callback. So it cannot yield. An exception is returned if it is
6625 * called from another callback. If nothing was copied, a nil value is pushed on
6626 * the stack.
6627 */
6628__LJMP static int hlua_http_msg_get_body(lua_State *L)
6629{
6630 struct http_msg *msg;
6631 struct filter *filter;
6632 size_t output, input;
6633 int offset, len;
6634
6635 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
6636 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
6637 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6638
6639 if (msg->msg_state < HTTP_MSG_DATA)
6640 WILL_LJMP(lua_error(L));
6641
6642 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6643 if (!filter || !hlua_filter_from_payload(filter))
6644 WILL_LJMP(lua_error(L));
6645
6646 if (!ci_data(msg->chn) && channel_input_closed(msg->chn)) {
6647 lua_pushnil(L);
6648 return 1;
6649 }
6650
6651 offset = output;
6652 if (lua_gettop(L) > 1) {
6653 offset = MAY_LJMP(luaL_checkinteger(L, 2));
6654 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006655 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006656 offset += output;
6657 if (offset < output || offset > input + output) {
6658 lua_pushfstring(L, "offset out of range.");
6659 WILL_LJMP(lua_error(L));
6660 }
6661 }
6662 len = output + input - offset;
6663 if (lua_gettop(L) == 3) {
6664 len = MAY_LJMP(luaL_checkinteger(L, 3));
6665 if (!len)
6666 goto dup;
6667 if (len == -1)
6668 len = global.tune.bufsize;
6669 if (len < 0) {
6670 lua_pushfstring(L, "length out of range.");
6671 WILL_LJMP(lua_error(L));
6672 }
6673 }
6674
6675 dup:
6676 _hlua_http_msg_dup(msg, L, offset, len);
6677 return 1;
6678}
6679
6680/* Appends a string to the HTTP message, after all existing DATA blocks but
6681 * before the trailers, if any. It returns the amount of data written or -1 if
6682 * nothing was copied. Unlike the channel function used to append data, this one
6683 * can only be called inside a filter, from http_payload callback. So it cannot
6684 * yield. An exception is returned if it is called from another callback.
6685 */
6686__LJMP static int hlua_http_msg_append(lua_State *L)
6687{
6688 struct http_msg *msg;
6689 struct filter *filter;
6690 const char *str;
6691 size_t offset, len, sz;
6692 int ret;
6693
6694 MAY_LJMP(check_args(L, 2, "append"));
6695 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6696
6697 if (msg->msg_state < HTTP_MSG_DATA)
6698 WILL_LJMP(lua_error(L));
6699
6700 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6701 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6702 if (!filter || !hlua_filter_from_payload(filter))
6703 WILL_LJMP(lua_error(L));
6704
6705 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset+len);
6706 lua_pushinteger(L, ret);
6707 return 1;
6708}
6709
6710/* Prepends a string to the HTTP message, before all existing DATA blocks. It
6711 * returns the amount of data written or -1 if nothing was copied. Unlike the
6712 * channel function used to prepend data, this one can only be called inside a
6713 * filter, from http_payload callback. So it cannot yield. An exception is
6714 * returned if it is called from another callback.
6715 */
6716__LJMP static int hlua_http_msg_prepend(lua_State *L)
6717{
6718 struct http_msg *msg;
6719 struct filter *filter;
6720 const char *str;
6721 size_t offset, len, sz;
6722 int ret;
6723
6724 MAY_LJMP(check_args(L, 2, "prepend"));
6725 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006726
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006727 if (msg->msg_state < HTTP_MSG_DATA)
6728 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006729
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006730 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6731 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6732 if (!filter || !hlua_filter_from_payload(filter))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006733 WILL_LJMP(lua_error(L));
6734
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006735 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6736 lua_pushinteger(L, ret);
6737 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006738}
6739
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006740/* Inserts a string to the HTTP message at a given offset. By default the string
6741 * is appended at the end of DATA blocks. It returns the amount of data written
6742 * or -1 if nothing was copied. Unlike the channel function used to insert data,
6743 * this one can only be called inside a filter, from http_payload callback. So
6744 * it cannot yield. An exception is returned if it is called from another
6745 * callback.
6746 */
6747__LJMP static int hlua_http_msg_insert_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006748{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006749 struct http_msg *msg;
6750 struct filter *filter;
6751 const char *str;
6752 size_t input, output, sz;
6753 int offset;
6754 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006755
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006756 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
6757 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006758 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006759
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006760 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006761 WILL_LJMP(lua_error(L));
6762
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006763 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006764 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006765 if (!filter || !hlua_filter_from_payload(filter))
6766 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006767
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006768 offset = output;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006769 if (lua_gettop(L) > 2) {
6770 offset = MAY_LJMP(luaL_checkinteger(L, 3));
6771 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006772 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006773 offset += output;
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006774 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006775 lua_pushfstring(L, "offset out of range.");
6776 WILL_LJMP(lua_error(L));
6777 }
6778 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006779
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006780 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6781 lua_pushinteger(L, ret);
6782 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006783}
6784
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006785/* Removes a given amount of data from the HTTP message at a given offset. By
6786 * default all DATA blocks are removed. It returns the amount of data
6787 * removed. Unlike the channel function used to remove data, this one can only
6788 * be called inside a filter, from http_payload callback. So it cannot yield. An
6789 * exception is returned if it is called from another callback.
6790 */
6791__LJMP static int hlua_http_msg_del_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006792{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006793 struct http_msg *msg;
6794 struct filter *filter;
6795 size_t input, output;
6796 int offset, len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006797
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006798 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
Boyang Lie0c54352022-05-10 17:47:23 +00006799 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006800 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006801
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006802 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006803 WILL_LJMP(lua_error(L));
6804
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006805 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006806 if (!filter || !hlua_filter_from_payload(filter))
6807 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006808
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006809 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00006810 if (lua_gettop(L) > 1) {
6811 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006812 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006813 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006814 offset += output;
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006815 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006816 lua_pushfstring(L, "offset out of range.");
6817 WILL_LJMP(lua_error(L));
6818 }
6819 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006820
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006821 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00006822 if (lua_gettop(L) == 3) {
6823 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006824 if (!len)
6825 goto end;
6826 if (len == -1)
6827 len = output + input - offset;
6828 if (len < 0 || offset + len > output + input) {
6829 lua_pushfstring(L, "length out of range.");
6830 WILL_LJMP(lua_error(L));
6831 }
6832 }
6833
6834 _hlua_http_msg_delete(msg, filter, offset, len);
6835
6836 end:
6837 lua_pushinteger(L, len);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006838 return 1;
6839}
6840
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006841/* Replaces a given amount of data at the given offset by a string. By default,
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006842 * all remaining data are removed, accordingly to the filter context. It returns
6843 * the amount of data written or -1 if nothing was copied. Unlike the channel
6844 * function used to replace data, this one can only be called inside a filter,
6845 * from http_payload callback. So it cannot yield. An exception is returned if
6846 * it is called from another callback.
6847 */
6848__LJMP static int hlua_http_msg_set_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006849{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006850 struct http_msg *msg;
6851 struct filter *filter;
6852 struct htx *htx;
6853 const char *str;
6854 size_t input, output, sz;
6855 int offset, len;
6856 int ret;
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02006857
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006858 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
6859 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
6860 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6861
6862 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006863 WILL_LJMP(lua_error(L));
6864
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006865 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6866 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6867 if (!filter || !hlua_filter_from_payload(filter))
6868 WILL_LJMP(lua_error(L));
6869
6870 offset = output;
6871 if (lua_gettop(L) > 2) {
6872 offset = MAY_LJMP(luaL_checkinteger(L, 3));
6873 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006874 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006875 offset += output;
6876 if (offset < output || offset > input + output) {
6877 lua_pushfstring(L, "offset out of range.");
6878 WILL_LJMP(lua_error(L));
6879 }
6880 }
6881
6882 len = output + input - offset;
6883 if (lua_gettop(L) == 4) {
6884 len = MAY_LJMP(luaL_checkinteger(L, 4));
6885 if (!len)
6886 goto set;
6887 if (len == -1)
6888 len = output + input - offset;
6889 if (len < 0 || offset + len > output + input) {
6890 lua_pushfstring(L, "length out of range.");
6891 WILL_LJMP(lua_error(L));
6892 }
6893 }
6894
6895 set:
6896 /* Be sure we can copied the string once input data will be removed. */
6897 htx = htx_from_buf(&msg->chn->buf);
6898 if (sz > htx_free_data_space(htx) + len)
6899 lua_pushinteger(L, -1);
6900 else {
6901 _hlua_http_msg_delete(msg, filter, offset, len);
6902 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6903 lua_pushinteger(L, ret);
6904 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006905 return 1;
6906}
6907
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006908/* Prepends data into an HTTP message and forward it, from the filter point of
6909 * view. It returns the amount of data written or -1 if nothing was sent. Unlike
6910 * the channel function used to send data, this one can only be called inside a
6911 * filter, from http_payload callback. So it cannot yield. An exception is
6912 * returned if it is called from another callback.
6913 */
6914__LJMP static int hlua_http_msg_send(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006915{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006916 struct http_msg *msg;
6917 struct filter *filter;
6918 struct htx *htx;
6919 const char *str;
6920 size_t offset, len, sz;
6921 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006922
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006923 MAY_LJMP(check_args(L, 2, "send"));
6924 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6925
6926 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006927 WILL_LJMP(lua_error(L));
6928
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006929 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6930 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6931 if (!filter || !hlua_filter_from_payload(filter))
6932 WILL_LJMP(lua_error(L));
6933
6934 /* Return an error if the channel's output is closed */
6935 if (unlikely(channel_output_closed(msg->chn))) {
6936 lua_pushinteger(L, -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006937 return 1;
6938 }
6939
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006940 htx = htx_from_buf(&msg->chn->buf);
6941 if (sz > htx_free_data_space(htx)) {
6942 lua_pushinteger(L, -1);
6943 return 1;
6944 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006945
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006946 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6947 if (ret > 0) {
6948 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6949
6950 FLT_OFF(filter, msg->chn) += ret;
6951 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
6952 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
6953 }
6954
6955 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006956 return 1;
6957}
6958
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006959/* Forwards a given amount of bytes. It return -1 if the channel's output is
6960 * closed. Otherwise, it returns the number of bytes forwarded. Unlike the
6961 * channel function used to forward data, this one can only be called inside a
6962 * filter, from http_payload callback. So it cannot yield. An exception is
6963 * returned if it is called from another callback. All other functions deal with
6964 * DATA block, this one not.
6965*/
6966__LJMP static int hlua_http_msg_forward(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006967{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006968 struct http_msg *msg;
6969 struct filter *filter;
6970 size_t offset, len;
6971 int fwd, ret = 0;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006972
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006973 MAY_LJMP(check_args(L, 2, "forward"));
6974 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6975
6976 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006977 WILL_LJMP(lua_error(L));
6978
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006979 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
6980 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6981 if (!filter || !hlua_filter_from_payload(filter))
6982 WILL_LJMP(lua_error(L));
6983
6984 /* Nothing to do, just return */
6985 if (!fwd)
6986 goto end;
6987
6988 /* Return an error if the channel's output is closed */
6989 if (unlikely(channel_output_closed(msg->chn))) {
6990 ret = -1;
6991 goto end;
6992 }
6993
6994 ret = fwd;
6995 if (ret > len)
6996 ret = len;
6997
6998 if (ret) {
6999 struct hlua_flt_ctx *flt_ctx = filter->ctx;
7000
7001 FLT_OFF(filter, msg->chn) += ret;
7002 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
7003 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
7004 }
7005
7006 end:
7007 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007008 return 1;
7009}
7010
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007011/* Set EOM flag on the HTX message.
7012 *
7013 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7014 * really know how to do without this feature.
7015 */
7016__LJMP static int hlua_http_msg_set_eom(lua_State *L)
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007017{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007018 struct http_msg *msg;
7019 struct htx *htx;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007020
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007021 MAY_LJMP(check_args(L, 1, "set_eom"));
7022 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7023 htx = htxbuf(&msg->chn->buf);
7024 htx->flags |= HTX_FL_EOM;
7025 return 0;
7026}
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007027
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007028/* Unset EOM flag on the HTX message.
7029 *
7030 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7031 * really know how to do without this feature.
7032 */
7033__LJMP static int hlua_http_msg_unset_eom(lua_State *L)
7034{
7035 struct http_msg *msg;
7036 struct htx *htx;
7037
7038 MAY_LJMP(check_args(L, 1, "set_eom"));
7039 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7040 htx = htxbuf(&msg->chn->buf);
7041 htx->flags &= ~HTX_FL_EOM;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007042 return 0;
7043}
7044
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007045/*
7046 *
7047 *
William Lallemand3956c4e2021-09-21 16:25:15 +02007048 * Class HTTPClient
7049 *
7050 *
7051 */
7052__LJMP static struct hlua_httpclient *hlua_checkhttpclient(lua_State *L, int ud)
7053{
7054 return MAY_LJMP(hlua_checkudata(L, ud, class_httpclient_ref));
7055}
7056
William Lallemandf77f1de2021-09-28 19:10:38 +02007057
7058/* stops the httpclient and ask it to kill itself */
7059__LJMP static int hlua_httpclient_gc(lua_State *L)
7060{
7061 struct hlua_httpclient *hlua_hc;
7062
7063 MAY_LJMP(check_args(L, 1, "__gc"));
7064
7065 hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
7066
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007067 if (MT_LIST_DELETE(&hlua_hc->by_hlua)) {
7068 /* we won the race against hlua_httpclient_destroy_all() */
William Lallemandbb581422022-10-20 10:57:28 +02007069 httpclient_stop_and_destroy(hlua_hc->hc);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007070 hlua_hc->hc = NULL;
7071 }
William Lallemandf77f1de2021-09-28 19:10:38 +02007072
7073 return 0;
7074}
7075
7076
William Lallemand3956c4e2021-09-21 16:25:15 +02007077__LJMP static int hlua_httpclient_new(lua_State *L)
7078{
7079 struct hlua_httpclient *hlua_hc;
7080 struct hlua *hlua;
7081
7082 /* Get hlua struct, or NULL if we execute from main lua state */
7083 hlua = hlua_gethlua(L);
7084 if (!hlua)
7085 return 0;
7086
7087 /* Check stack size. */
7088 if (!lua_checkstack(L, 3)) {
7089 hlua_pusherror(L, "httpclient: full stack");
7090 goto err;
7091 }
7092 /* Create the object: obj[0] = userdata. */
7093 lua_newtable(L);
7094 hlua_hc = MAY_LJMP(lua_newuserdata(L, sizeof(*hlua_hc)));
7095 lua_rawseti(L, -2, 0);
7096 memset(hlua_hc, 0, sizeof(*hlua_hc));
7097
7098 hlua_hc->hc = httpclient_new(hlua, 0, IST_NULL);
7099 if (!hlua_hc->hc)
7100 goto err;
7101
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007102 MT_LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
William Lallemandbb581422022-10-20 10:57:28 +02007103
William Lallemand3956c4e2021-09-21 16:25:15 +02007104 /* Pop a class stream metatable and affect it to the userdata. */
7105 lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
7106 lua_setmetatable(L, -2);
7107
7108 return 1;
7109
7110 err:
7111 WILL_LJMP(lua_error(L));
7112 return 0;
7113}
7114
7115
7116/*
7117 * Callback of the httpclient, this callback wakes the lua task up, once the
7118 * httpclient receives some data
7119 *
7120 */
7121
William Lallemandbd5739e2021-10-28 15:41:38 +02007122static void hlua_httpclient_cb(struct httpclient *hc)
William Lallemand3956c4e2021-09-21 16:25:15 +02007123{
7124 struct hlua *hlua = hc->caller;
7125
7126 if (!hlua || !hlua->task)
7127 return;
7128
7129 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7130}
7131
7132/*
William Lallemandd7df73a2021-09-23 17:54:00 +02007133 * Fill the lua stack with headers from the httpclient response
7134 * This works the same way as the hlua_http_get_headers() function
7135 */
7136__LJMP static int hlua_httpclient_get_headers(lua_State *L, struct hlua_httpclient *hlua_hc)
7137{
7138 struct http_hdr *hdr;
7139
7140 lua_newtable(L);
7141
William Lallemandef574b22021-10-05 16:19:31 +02007142 for (hdr = hlua_hc->hc->res.hdrs; hdr && isttest(hdr->n); hdr++) {
William Lallemandd7df73a2021-09-23 17:54:00 +02007143 struct ist n, v;
7144 int len;
7145
7146 n = hdr->n;
7147 v = hdr->v;
7148
7149 /* Check for existing entry:
7150 * assume that the table is on the top of the stack, and
7151 * push the key in the stack, the function lua_gettable()
7152 * perform the lookup.
7153 */
7154
7155 lua_pushlstring(L, n.ptr, n.len);
7156 lua_gettable(L, -2);
7157
7158 switch (lua_type(L, -1)) {
7159 case LUA_TNIL:
7160 /* Table not found, create it. */
7161 lua_pop(L, 1); /* remove the nil value. */
7162 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
7163 lua_newtable(L); /* create and push empty table. */
7164 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7165 lua_rawseti(L, -2, 0); /* index header value (pop it). */
7166 lua_rawset(L, -3); /* index new table with header name (pop the values). */
7167 break;
7168
7169 case LUA_TTABLE:
7170 /* Entry found: push the value in the table. */
7171 len = lua_rawlen(L, -1);
7172 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7173 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
7174 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
7175 break;
7176
7177 default:
7178 /* Other cases are errors. */
7179 hlua_pusherror(L, "internal error during the parsing of headers.");
7180 WILL_LJMP(lua_error(L));
7181 }
7182 }
7183 return 1;
7184}
7185
7186/*
William Lallemand746e6f32021-10-06 10:57:44 +02007187 * Allocate and return an array of http_hdr ist extracted from the <headers> lua table
7188 *
7189 * Caller must free the result
7190 */
7191struct http_hdr *hlua_httpclient_table_to_hdrs(lua_State *L)
7192{
7193 struct http_hdr hdrs[global.tune.max_http_hdr];
7194 struct http_hdr *result = NULL;
7195 uint32_t hdr_num = 0;
7196
7197 lua_pushnil(L);
7198 while (lua_next(L, -2) != 0) {
7199 struct ist name, value;
7200 const char *n, *v;
7201 size_t nlen, vlen;
7202
7203 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
7204 /* Skip element if the key is not a string or if the value is not a table */
7205 goto next_hdr;
7206 }
7207
7208 n = lua_tolstring(L, -2, &nlen);
7209 name = ist2(n, nlen);
7210
7211 /* Loop on header's values */
7212 lua_pushnil(L);
7213 while (lua_next(L, -2)) {
7214 if (!lua_isstring(L, -1)) {
7215 /* Skip the value if it is not a string */
7216 goto next_value;
7217 }
7218
7219 v = lua_tolstring(L, -1, &vlen);
7220 value = ist2(v, vlen);
7221 name = ist2(n, nlen);
7222
7223 hdrs[hdr_num].n = istdup(name);
7224 hdrs[hdr_num].v = istdup(value);
7225
7226 hdr_num++;
7227
7228 next_value:
7229 lua_pop(L, 1);
7230 }
7231
7232 next_hdr:
7233 lua_pop(L, 1);
7234
7235 }
7236
7237 if (hdr_num) {
7238 /* alloc and copy the headers in the httpclient struct */
Tim Duesterhus16cc16d2021-11-06 15:14:45 +01007239 result = calloc((hdr_num + 1), sizeof(*result));
William Lallemand746e6f32021-10-06 10:57:44 +02007240 if (!result)
7241 goto skip_headers;
7242 memcpy(result, hdrs, sizeof(struct http_hdr) * (hdr_num + 1));
7243
7244 result[hdr_num].n = IST_NULL;
7245 result[hdr_num].v = IST_NULL;
7246 }
7247
7248skip_headers:
William Lallemand746e6f32021-10-06 10:57:44 +02007249
7250 return result;
7251}
7252
7253
William Lallemandbd5739e2021-10-28 15:41:38 +02007254/*
7255 * For each yield, checks if there is some data in the httpclient and push them
7256 * in the lua buffer, once the httpclient finished its job, push the result on
7257 * the stack
7258 */
7259__LJMP static int hlua_httpclient_rcv_yield(lua_State *L, int status, lua_KContext ctx)
7260{
7261 struct buffer *tr;
7262 int res;
7263 struct hlua *hlua = hlua_gethlua(L);
7264 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7265
7266
7267 tr = get_trash_chunk();
7268
7269 res = httpclient_res_xfer(hlua_hc->hc, tr);
7270 luaL_addlstring(&hlua_hc->b, b_orig(tr), res);
7271
7272 if (!httpclient_data(hlua_hc->hc) && httpclient_ended(hlua_hc->hc)) {
7273
7274 luaL_pushresult(&hlua_hc->b);
7275 lua_settable(L, -3);
7276
7277 lua_pushstring(L, "status");
7278 lua_pushinteger(L, hlua_hc->hc->res.status);
7279 lua_settable(L, -3);
7280
7281
7282 lua_pushstring(L, "reason");
7283 lua_pushlstring(L, hlua_hc->hc->res.reason.ptr, hlua_hc->hc->res.reason.len);
7284 lua_settable(L, -3);
7285
7286 lua_pushstring(L, "headers");
7287 hlua_httpclient_get_headers(L, hlua_hc);
7288 lua_settable(L, -3);
7289
7290 return 1;
7291 }
7292
7293 if (httpclient_data(hlua_hc->hc))
7294 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7295
7296 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7297
7298 return 0;
7299}
7300
7301/*
7302 * Call this when trying to stream a body during a request
7303 */
7304__LJMP static int hlua_httpclient_snd_yield(lua_State *L, int status, lua_KContext ctx)
7305{
7306 struct hlua *hlua;
7307 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7308 const char *body_str = NULL;
7309 int ret;
7310 int end = 0;
7311 size_t buf_len;
7312 size_t to_send = 0;
7313
7314 hlua = hlua_gethlua(L);
7315
7316 if (!hlua || !hlua->task)
7317 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7318 "'frontend', 'backend' or 'task'"));
7319
7320 ret = lua_getfield(L, -1, "body");
7321 if (ret != LUA_TSTRING)
7322 goto rcv;
7323
7324 body_str = lua_tolstring(L, -1, &buf_len);
7325 lua_pop(L, 1);
7326
Christopher Fauletfc591292022-01-12 14:46:03 +01007327 to_send = buf_len - hlua_hc->sent;
William Lallemandbd5739e2021-10-28 15:41:38 +02007328
7329 if ((hlua_hc->sent + to_send) >= buf_len)
7330 end = 1;
7331
7332 /* the end flag is always set since we are using the whole remaining size */
7333 hlua_hc->sent += httpclient_req_xfer(hlua_hc->hc, ist2(body_str + hlua_hc->sent, to_send), end);
7334
7335 if (buf_len > hlua_hc->sent) {
7336 /* still need to process the buffer */
7337 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
7338 } else {
7339 goto rcv;
7340 /* we sent the whole request buffer we can recv */
7341 }
7342 return 0;
7343
7344rcv:
7345
7346 /* we return a "res" object */
7347 lua_newtable(L);
7348
William Lallemandbd5739e2021-10-28 15:41:38 +02007349 lua_pushstring(L, "body");
William Lallemandd1187eb2021-11-02 10:40:06 +01007350 luaL_buffinit(L, &hlua_hc->b);
William Lallemandbd5739e2021-10-28 15:41:38 +02007351
William Lallemand933fe392021-11-04 09:45:58 +01007352 task_wakeup(hlua->task, TASK_WOKEN_MSG);
William Lallemandbd5739e2021-10-28 15:41:38 +02007353 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7354
7355 return 1;
7356}
William Lallemand746e6f32021-10-06 10:57:44 +02007357
William Lallemand3956c4e2021-09-21 16:25:15 +02007358/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007359 * Send an HTTP request and wait for a response
William Lallemand3956c4e2021-09-21 16:25:15 +02007360 */
7361
William Lallemanddc2cc902021-10-26 11:43:26 +02007362__LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
William Lallemand3956c4e2021-09-21 16:25:15 +02007363{
7364 struct hlua_httpclient *hlua_hc;
William Lallemand746e6f32021-10-06 10:57:44 +02007365 struct http_hdr *hdrs = NULL;
7366 struct http_hdr *hdrs_i = NULL;
William Lallemand3956c4e2021-09-21 16:25:15 +02007367 struct hlua *hlua;
William Lallemand746e6f32021-10-06 10:57:44 +02007368 const char *url_str = NULL;
William Lallemanddec25c32021-10-25 19:48:37 +02007369 const char *body_str = NULL;
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007370 size_t buf_len = 0;
William Lallemand746e6f32021-10-06 10:57:44 +02007371 int ret;
William Lallemand3956c4e2021-09-21 16:25:15 +02007372
7373 hlua = hlua_gethlua(L);
7374
7375 if (!hlua || !hlua->task)
7376 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7377 "'frontend', 'backend' or 'task'"));
7378
William Lallemand746e6f32021-10-06 10:57:44 +02007379 if (lua_gettop(L) != 2 || lua_type(L, -1) != LUA_TTABLE)
7380 WILL_LJMP(luaL_error(L, "'get' needs a table as argument"));
7381
William Lallemand4f4f2b72022-02-17 20:00:23 +01007382 hlua_hc = hlua_checkhttpclient(L, 1);
7383
William Lallemand7177a952022-03-03 15:33:12 +01007384 lua_pushnil(L); /* first key */
7385 while (lua_next(L, 2)) {
7386 if (strcmp(lua_tostring(L, -2), "dst") == 0) {
7387 if (httpclient_set_dst(hlua_hc->hc, lua_tostring(L, -1)) < 0)
7388 WILL_LJMP(luaL_error(L, "Can't use the 'dst' argument"));
William Lallemand4f4f2b72022-02-17 20:00:23 +01007389
William Lallemand7177a952022-03-03 15:33:12 +01007390 } else if (strcmp(lua_tostring(L, -2), "url") == 0) {
7391 if (lua_type(L, -1) != LUA_TSTRING)
7392 WILL_LJMP(luaL_error(L, "invalid parameter in 'url', must be a string"));
7393 url_str = lua_tostring(L, -1);
William Lallemand3956c4e2021-09-21 16:25:15 +02007394
William Lallemand7177a952022-03-03 15:33:12 +01007395 } else if (strcmp(lua_tostring(L, -2), "timeout") == 0) {
7396 if (lua_type(L, -1) != LUA_TNUMBER)
7397 WILL_LJMP(luaL_error(L, "invalid parameter in 'timeout', must be a number"));
7398 httpclient_set_timeout(hlua_hc->hc, lua_tointeger(L, -1));
William Lallemandb4a4ef62022-02-23 14:18:16 +01007399
William Lallemand7177a952022-03-03 15:33:12 +01007400 } else if (strcmp(lua_tostring(L, -2), "headers") == 0) {
7401 if (lua_type(L, -1) != LUA_TTABLE)
7402 WILL_LJMP(luaL_error(L, "invalid parameter in 'headers', must be a table"));
7403 hdrs = hlua_httpclient_table_to_hdrs(L);
William Lallemand79416cb2021-09-24 14:51:44 +02007404
William Lallemand7177a952022-03-03 15:33:12 +01007405 } else if (strcmp(lua_tostring(L, -2), "body") == 0) {
7406 if (lua_type(L, -1) != LUA_TSTRING)
7407 WILL_LJMP(luaL_error(L, "invalid parameter in 'body', must be a string"));
7408 body_str = lua_tolstring(L, -1, &buf_len);
William Lallemandbd5739e2021-10-28 15:41:38 +02007409
William Lallemand7177a952022-03-03 15:33:12 +01007410 } else {
7411 WILL_LJMP(luaL_error(L, "'%s' invalid parameter name", lua_tostring(L, -2)));
7412 }
7413 /* removes 'value'; keeps 'key' for next iteration */
7414 lua_pop(L, 1);
7415 }
William Lallemanddec25c32021-10-25 19:48:37 +02007416
William Lallemand746e6f32021-10-06 10:57:44 +02007417 if (!url_str) {
7418 WILL_LJMP(luaL_error(L, "'get' need a 'url' argument"));
7419 return 0;
7420 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007421
William Lallemand10a37362022-03-02 16:18:26 +01007422 hlua_hc->sent = 0;
William Lallemand3956c4e2021-09-21 16:25:15 +02007423
Aurelien DARRAGON03564072023-02-09 15:26:25 +01007424 istfree(&hlua_hc->hc->req.url);
William Lallemand3956c4e2021-09-21 16:25:15 +02007425 hlua_hc->hc->req.url = istdup(ist(url_str));
William Lallemanddc2cc902021-10-26 11:43:26 +02007426 hlua_hc->hc->req.meth = meth;
William Lallemand3956c4e2021-09-21 16:25:15 +02007427
7428 /* update the httpclient callbacks */
William Lallemandbd5739e2021-10-28 15:41:38 +02007429 hlua_hc->hc->ops.res_stline = hlua_httpclient_cb;
7430 hlua_hc->hc->ops.res_headers = hlua_httpclient_cb;
7431 hlua_hc->hc->ops.res_payload = hlua_httpclient_cb;
William Lallemand8f170c72022-03-15 10:52:07 +01007432 hlua_hc->hc->ops.res_end = hlua_httpclient_cb;
William Lallemand3956c4e2021-09-21 16:25:15 +02007433
William Lallemandbd5739e2021-10-28 15:41:38 +02007434 /* a body is available, it will use the request callback */
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007435 if (body_str && buf_len) {
William Lallemandbd5739e2021-10-28 15:41:38 +02007436 hlua_hc->hc->ops.req_payload = hlua_httpclient_cb;
7437 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007438
William Lallemandbd5739e2021-10-28 15:41:38 +02007439 ret = httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, meth, hdrs, IST_NULL);
William Lallemand3956c4e2021-09-21 16:25:15 +02007440
William Lallemand746e6f32021-10-06 10:57:44 +02007441 /* free the temporary headers array */
7442 hdrs_i = hdrs;
7443 while (hdrs_i && isttest(hdrs_i->n)) {
7444 istfree(&hdrs_i->n);
7445 istfree(&hdrs_i->v);
7446 hdrs_i++;
7447 }
7448 ha_free(&hdrs);
7449
7450
William Lallemand6137a9e2021-10-26 15:01:53 +02007451 if (ret != ERR_NONE) {
7452 WILL_LJMP(luaL_error(L, "Can't generate the HTTP request"));
7453 return 0;
7454 }
7455
William Lallemandc2d3db42022-04-26 11:46:13 +02007456 if (!httpclient_start(hlua_hc->hc))
7457 WILL_LJMP(luaL_error(L, "couldn't start the httpclient"));
William Lallemand6137a9e2021-10-26 15:01:53 +02007458
William Lallemandbd5739e2021-10-28 15:41:38 +02007459 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
William Lallemand3956c4e2021-09-21 16:25:15 +02007460
William Lallemand3956c4e2021-09-21 16:25:15 +02007461 return 0;
7462}
7463
7464/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007465 * Sends an HTTP HEAD request and wait for a response
7466 *
7467 * httpclient:head(url, headers, payload)
7468 */
7469__LJMP static int hlua_httpclient_head(lua_State *L)
7470{
7471 return hlua_httpclient_send(L, HTTP_METH_HEAD);
7472}
7473
7474/*
7475 * Send an HTTP GET request and wait for a response
7476 *
7477 * httpclient:get(url, headers, payload)
7478 */
7479__LJMP static int hlua_httpclient_get(lua_State *L)
7480{
7481 return hlua_httpclient_send(L, HTTP_METH_GET);
7482
7483}
7484
7485/*
7486 * Sends an HTTP PUT request and wait for a response
7487 *
7488 * httpclient:put(url, headers, payload)
7489 */
7490__LJMP static int hlua_httpclient_put(lua_State *L)
7491{
7492 return hlua_httpclient_send(L, HTTP_METH_PUT);
7493}
7494
7495/*
7496 * Send an HTTP POST request and wait for a response
7497 *
7498 * httpclient:post(url, headers, payload)
7499 */
7500__LJMP static int hlua_httpclient_post(lua_State *L)
7501{
7502 return hlua_httpclient_send(L, HTTP_METH_POST);
7503}
7504
7505
7506/*
7507 * Sends an HTTP DELETE request and wait for a response
7508 *
7509 * httpclient:delete(url, headers, payload)
7510 */
7511__LJMP static int hlua_httpclient_delete(lua_State *L)
7512{
7513 return hlua_httpclient_send(L, HTTP_METH_DELETE);
7514}
7515
7516/*
William Lallemand3956c4e2021-09-21 16:25:15 +02007517 *
7518 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007519 * Class TXN
7520 *
7521 *
7522 */
7523
7524/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02007525 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007526 */
7527__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
7528{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007529 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007530}
7531
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007532__LJMP static int hlua_set_var(lua_State *L)
7533{
7534 struct hlua_txn *htxn;
7535 const char *name;
7536 size_t len;
7537 struct sample smp;
7538
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007539 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7540 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007541
7542 /* It is useles to retrieve the stream, but this function
7543 * runs only in a stream context.
7544 */
7545 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7546 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7547
7548 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01007549 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007550 hlua_lua2smp(L, 3, &smp);
7551
7552 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01007553 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007554
7555 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
7556 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
7557 else
7558 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
7559
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007560 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007561}
7562
Christopher Faulet85d79c92016-11-09 16:54:56 +01007563__LJMP static int hlua_unset_var(lua_State *L)
7564{
7565 struct hlua_txn *htxn;
7566 const char *name;
7567 size_t len;
7568 struct sample smp;
7569
7570 MAY_LJMP(check_args(L, 2, "unset_var"));
7571
7572 /* It is useles to retrieve the stream, but this function
7573 * runs only in a stream context.
7574 */
7575 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7576 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7577
7578 /* Unset the variable. */
7579 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007580 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
7581 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01007582}
7583
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007584__LJMP static int hlua_get_var(lua_State *L)
7585{
7586 struct hlua_txn *htxn;
7587 const char *name;
7588 size_t len;
7589 struct sample smp;
7590
7591 MAY_LJMP(check_args(L, 2, "get_var"));
7592
7593 /* It is useles to retrieve the stream, but this function
7594 * runs only in a stream context.
7595 */
7596 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7597 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7598
Willy Tarreau7560dd42016-03-10 16:28:58 +01007599 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02007600 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007601 lua_pushnil(L);
7602 return 1;
7603 }
7604
7605 return hlua_smp2lua(L, &smp);
7606}
7607
Willy Tarreau59551662015-03-10 14:23:13 +01007608__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007609{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007610 struct hlua *hlua;
7611
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007612 MAY_LJMP(check_args(L, 2, "set_priv"));
7613
Willy Tarreau87b09662015-04-03 00:22:06 +02007614 /* It is useles to retrieve the stream, but this function
7615 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007616 */
7617 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007618
7619 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007620 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007621 if (!hlua)
7622 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007623
7624 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02007625 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007626
7627 /* Get and store new value. */
7628 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
7629 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
7630
7631 return 0;
7632}
7633
Willy Tarreau59551662015-03-10 14:23:13 +01007634__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007635{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007636 struct hlua *hlua;
7637
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007638 MAY_LJMP(check_args(L, 1, "get_priv"));
7639
Willy Tarreau87b09662015-04-03 00:22:06 +02007640 /* It is useles to retrieve the stream, but this function
7641 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007642 */
7643 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007644
7645 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007646 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007647 if (!hlua) {
7648 lua_pushnil(L);
7649 return 1;
7650 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007651
7652 /* Push configuration index in the stack. */
7653 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
7654
7655 return 1;
7656}
7657
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007658/* Create stack entry containing a class TXN. This function
7659 * return 0 if the stack does not contains free slots,
7660 * otherwise it returns 1.
7661 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007662static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007663{
Willy Tarreaude491382015-04-06 11:04:28 +02007664 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007665
7666 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007667 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007668 return 0;
7669
7670 /* NOTE: The allocation never fails. The failure
7671 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007672 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007673 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007674 /* Create the object: obj[0] = userdata. */
7675 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02007676 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007677 lua_rawseti(L, -2, 0);
7678
Willy Tarreaude491382015-04-06 11:04:28 +02007679 htxn->s = s;
7680 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01007681 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007682 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007683
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007684 /* Create the "f" field that contains a list of fetches. */
7685 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007686 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007687 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007688 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007689
7690 /* Create the "sf" field that contains a list of stringsafe fetches. */
7691 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007692 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007693 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007694 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007695
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007696 /* Create the "c" field that contains a list of converters. */
7697 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02007698 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007699 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007700 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007701
7702 /* Create the "sc" field that contains a list of stringsafe converters. */
7703 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01007704 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007705 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007706 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007707
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007708 /* Create the "req" field that contains the request channel object. */
7709 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007710 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007711 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007712 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007713
7714 /* Create the "res" field that contains the response channel object. */
7715 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007716 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007717 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007718 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007719
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007720 /* Creates the HTTP object is the current proxy allows http. */
7721 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01007722 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02007723 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007724 return 0;
7725 }
7726 else
7727 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007728 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007729
Christopher Faulet78c35472020-02-26 17:14:08 +01007730 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX) {
7731 /* HTTPMessage object are created when a lua TXN is created from
7732 * a filter context only
7733 */
7734
7735 /* Creates the HTTP-Request object is the current proxy allows http. */
7736 lua_pushstring(L, "http_req");
7737 if (p->mode == PR_MODE_HTTP) {
7738 if (!hlua_http_msg_new(L, &s->txn->req))
7739 return 0;
7740 }
7741 else
7742 lua_pushnil(L);
7743 lua_rawset(L, -3);
7744
7745 /* Creates the HTTP-Response object is the current proxy allows http. */
7746 lua_pushstring(L, "http_res");
7747 if (p->mode == PR_MODE_HTTP) {
7748 if (!hlua_http_msg_new(L, &s->txn->rsp))
7749 return 0;
7750 }
7751 else
7752 lua_pushnil(L);
7753 lua_rawset(L, -3);
7754 }
7755
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007756 /* Pop a class sesison metatable and affect it to the userdata. */
7757 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
7758 lua_setmetatable(L, -2);
7759
7760 return 1;
7761}
7762
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01007763__LJMP static int hlua_txn_deflog(lua_State *L)
7764{
7765 const char *msg;
7766 struct hlua_txn *htxn;
7767
7768 MAY_LJMP(check_args(L, 2, "deflog"));
7769 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7770 msg = MAY_LJMP(luaL_checkstring(L, 2));
7771
7772 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
7773 return 0;
7774}
7775
7776__LJMP static int hlua_txn_log(lua_State *L)
7777{
7778 int level;
7779 const char *msg;
7780 struct hlua_txn *htxn;
7781
7782 MAY_LJMP(check_args(L, 3, "log"));
7783 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7784 level = MAY_LJMP(luaL_checkinteger(L, 2));
7785 msg = MAY_LJMP(luaL_checkstring(L, 3));
7786
7787 if (level < 0 || level >= NB_LOG_LEVELS)
7788 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
7789
7790 hlua_sendlog(htxn->s->be, level, msg);
7791 return 0;
7792}
7793
7794__LJMP static int hlua_txn_log_debug(lua_State *L)
7795{
7796 const char *msg;
7797 struct hlua_txn *htxn;
7798
7799 MAY_LJMP(check_args(L, 2, "Debug"));
7800 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7801 msg = MAY_LJMP(luaL_checkstring(L, 2));
7802 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
7803 return 0;
7804}
7805
7806__LJMP static int hlua_txn_log_info(lua_State *L)
7807{
7808 const char *msg;
7809 struct hlua_txn *htxn;
7810
7811 MAY_LJMP(check_args(L, 2, "Info"));
7812 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7813 msg = MAY_LJMP(luaL_checkstring(L, 2));
7814 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
7815 return 0;
7816}
7817
7818__LJMP static int hlua_txn_log_warning(lua_State *L)
7819{
7820 const char *msg;
7821 struct hlua_txn *htxn;
7822
7823 MAY_LJMP(check_args(L, 2, "Warning"));
7824 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7825 msg = MAY_LJMP(luaL_checkstring(L, 2));
7826 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
7827 return 0;
7828}
7829
7830__LJMP static int hlua_txn_log_alert(lua_State *L)
7831{
7832 const char *msg;
7833 struct hlua_txn *htxn;
7834
7835 MAY_LJMP(check_args(L, 2, "Alert"));
7836 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7837 msg = MAY_LJMP(luaL_checkstring(L, 2));
7838 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
7839 return 0;
7840}
7841
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007842__LJMP static int hlua_txn_set_loglevel(lua_State *L)
7843{
7844 struct hlua_txn *htxn;
7845 int ll;
7846
7847 MAY_LJMP(check_args(L, 2, "set_loglevel"));
7848 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7849 ll = MAY_LJMP(luaL_checkinteger(L, 2));
7850
7851 if (ll < 0 || ll > 7)
7852 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
7853
7854 htxn->s->logs.level = ll;
7855 return 0;
7856}
7857
7858__LJMP static int hlua_txn_set_tos(lua_State *L)
7859{
7860 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007861 int tos;
7862
7863 MAY_LJMP(check_args(L, 2, "set_tos"));
7864 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7865 tos = MAY_LJMP(luaL_checkinteger(L, 2));
7866
Willy Tarreau1a18b542018-12-11 16:37:42 +01007867 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007868 return 0;
7869}
7870
7871__LJMP static int hlua_txn_set_mark(lua_State *L)
7872{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007873 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007874 int mark;
7875
7876 MAY_LJMP(check_args(L, 2, "set_mark"));
7877 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7878 mark = MAY_LJMP(luaL_checkinteger(L, 2));
7879
Lukas Tribus579e3e32019-08-11 18:03:45 +02007880 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007881 return 0;
7882}
7883
Patrick Hemmer268a7072018-05-11 12:52:31 -04007884__LJMP static int hlua_txn_set_priority_class(lua_State *L)
7885{
7886 struct hlua_txn *htxn;
7887
7888 MAY_LJMP(check_args(L, 2, "set_priority_class"));
7889 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7890 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
7891 return 0;
7892}
7893
7894__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
7895{
7896 struct hlua_txn *htxn;
7897
7898 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
7899 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7900 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
7901 return 0;
7902}
7903
Christopher Faulet700d9e82020-01-31 12:21:52 +01007904/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007905 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01007906 * message and terminate the transaction. It returns 1 on success and 0 on
7907 * error. The Reply must be on top of the stack.
7908 */
7909__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
7910{
7911 struct htx *htx;
7912 struct htx_sl *sl;
7913 struct h1m h1m;
7914 const char *status, *reason, *body;
7915 size_t status_len, reason_len, body_len;
7916 int ret, code, flags;
7917
7918 code = 200;
7919 status = "200";
7920 status_len = 3;
7921 ret = lua_getfield(L, -1, "status");
7922 if (ret == LUA_TNUMBER) {
7923 code = lua_tointeger(L, -1);
7924 status = lua_tolstring(L, -1, &status_len);
7925 }
7926 lua_pop(L, 1);
7927
7928 reason = http_get_reason(code);
7929 reason_len = strlen(reason);
7930 ret = lua_getfield(L, -1, "reason");
7931 if (ret == LUA_TSTRING)
7932 reason = lua_tolstring(L, -1, &reason_len);
7933 lua_pop(L, 1);
7934
7935 body = NULL;
7936 body_len = 0;
7937 ret = lua_getfield(L, -1, "body");
7938 if (ret == LUA_TSTRING)
7939 body = lua_tolstring(L, -1, &body_len);
7940 lua_pop(L, 1);
7941
7942 /* Prepare the response before inserting the headers */
7943 h1m_init_res(&h1m);
7944 htx = htx_from_buf(&s->res.buf);
7945 channel_htx_truncate(&s->res, htx);
7946 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
7947 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
7948 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
7949 ist2(status, status_len), ist2(reason, reason_len));
7950 }
7951 else {
7952 flags = HTX_SL_F_IS_RESP;
7953 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
7954 ist2(status, status_len), ist2(reason, reason_len));
7955 }
7956 if (!sl)
7957 goto fail;
7958 sl->info.res.status = code;
7959
7960 /* Push in the stack the "headers" entry. */
7961 ret = lua_getfield(L, -1, "headers");
7962 if (ret != LUA_TTABLE)
7963 goto skip_headers;
7964
7965 lua_pushnil(L);
7966 while (lua_next(L, -2) != 0) {
7967 struct ist name, value;
7968 const char *n, *v;
7969 size_t nlen, vlen;
7970
7971 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
7972 /* Skip element if the key is not a string or if the value is not a table */
7973 goto next_hdr;
7974 }
7975
7976 n = lua_tolstring(L, -2, &nlen);
7977 name = ist2(n, nlen);
7978 if (isteqi(name, ist("content-length"))) {
7979 /* Always skip content-length header. It will be added
7980 * later with the correct len
7981 */
7982 goto next_hdr;
7983 }
7984
7985 /* Loop on header's values */
7986 lua_pushnil(L);
7987 while (lua_next(L, -2)) {
7988 if (!lua_isstring(L, -1)) {
7989 /* Skip the value if it is not a string */
7990 goto next_value;
7991 }
7992
7993 v = lua_tolstring(L, -1, &vlen);
7994 value = ist2(v, vlen);
7995
7996 if (isteqi(name, ist("transfer-encoding")))
7997 h1_parse_xfer_enc_header(&h1m, value);
7998 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
7999 goto fail;
8000
8001 next_value:
8002 lua_pop(L, 1);
8003 }
8004
8005 next_hdr:
8006 lua_pop(L, 1);
8007 }
8008 skip_headers:
8009 lua_pop(L, 1);
8010
8011 /* Update h1m flags: CLEN is set if CHNK is not present */
8012 if (!(h1m.flags & H1_MF_CHNK)) {
8013 const char *clen = ultoa(body_len);
8014
8015 h1m.flags |= H1_MF_CLEN;
8016 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
8017 goto fail;
8018 }
8019 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
8020 h1m.flags |= H1_MF_XFER_LEN;
8021
8022 /* Update HTX start-line flags */
8023 if (h1m.flags & H1_MF_XFER_ENC)
8024 flags |= HTX_SL_F_XFER_ENC;
8025 if (h1m.flags & H1_MF_XFER_LEN) {
8026 flags |= HTX_SL_F_XFER_LEN;
8027 if (h1m.flags & H1_MF_CHNK)
8028 flags |= HTX_SL_F_CHNK;
8029 else if (h1m.flags & H1_MF_CLEN)
8030 flags |= HTX_SL_F_CLEN;
8031 if (h1m.body_len == 0)
8032 flags |= HTX_SL_F_BODYLESS;
8033 }
8034 sl->flags |= flags;
8035
8036
8037 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008038 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01008039 goto fail;
8040
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008041 htx->flags |= HTX_FL_EOM;
8042
Christopher Faulet700d9e82020-01-31 12:21:52 +01008043 /* Now, forward the response and terminate the transaction */
8044 s->txn->status = code;
8045 htx_to_buf(htx, &s->res.buf);
8046 if (!http_forward_proxy_resp(s, 1))
8047 goto fail;
8048
8049 return 1;
8050
8051 fail:
8052 channel_htx_truncate(&s->res, htx);
8053 return 0;
8054}
8055
8056/* Terminate a transaction if called from a lua action. For TCP streams,
8057 * processing is just aborted. Nothing is returned to the client and all
8058 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
8059 * is forwarded to the client before terminating the transaction. On success,
8060 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
8061 * with ACT_RET_ERR code. If this function is not called from a lua action, it
8062 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008063 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008064__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008065{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008066 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01008067 struct stream *s;
8068 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008069
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008070 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008071
Christopher Faulet700d9e82020-01-31 12:21:52 +01008072 /* If the flags NOTERM is set, we cannot terminate the session, so we
8073 * just end the execution of the current lua code. */
8074 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008075 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008076
Christopher Faulet700d9e82020-01-31 12:21:52 +01008077 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008078 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008079 struct channel *req = &s->req;
8080 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01008081
Christopher Faulet700d9e82020-01-31 12:21:52 +01008082 channel_auto_read(req);
8083 channel_abort(req);
8084 channel_auto_close(req);
8085 channel_erase(req);
8086
Christopher Fauletf8413cb2023-02-07 16:06:14 +01008087 sc_ep_set_wex(s->scb, s->scf->wto);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008088 channel_auto_read(res);
8089 channel_auto_close(res);
8090 channel_shutr_now(res);
8091
8092 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
8093 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008094 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02008095
Christopher Faulet700d9e82020-01-31 12:21:52 +01008096 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
8097 /* No reply or invalid reply */
8098 s->txn->status = 0;
8099 http_reply_and_close(s, 0, NULL);
8100 }
8101 else {
8102 /* Remove extra args to have the reply on top of the stack */
8103 if (lua_gettop(L) > 2)
8104 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008105
Christopher Faulet700d9e82020-01-31 12:21:52 +01008106 if (!hlua_txn_forward_reply(L, s)) {
8107 if (!(s->flags & SF_ERR_MASK))
8108 s->flags |= SF_ERR_PRXCOND;
8109 lua_pushinteger(L, ACT_RET_ERR);
8110 WILL_LJMP(hlua_done(L));
8111 return 0; /* Never reached */
8112 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02008113 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008114
Christopher Faulet700d9e82020-01-31 12:21:52 +01008115 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
8116 if (htxn->dir == SMP_OPT_DIR_REQ) {
8117 /* let's log the request time */
8118 s->logs.tv_request = now;
8119 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02008120 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008121 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008122
Christopher Faulet700d9e82020-01-31 12:21:52 +01008123 done:
8124 if (!(s->flags & SF_ERR_MASK))
8125 s->flags |= SF_ERR_LOCAL;
8126 if (!(s->flags & SF_FINST_MASK))
8127 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008128
Christopher Faulete48d1dc2021-08-13 14:11:17 +02008129 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX)
8130 lua_pushinteger(L, -1);
8131 else
8132 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008133 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008134 return 0;
8135}
8136
Christopher Faulet700d9e82020-01-31 12:21:52 +01008137/*
8138 *
8139 *
8140 * Class REPLY
8141 *
8142 *
8143 */
8144
8145/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
8146 * free slots, the function fails and returns 0;
8147 */
8148static int hlua_txn_reply_new(lua_State *L)
8149{
8150 struct hlua_txn *htxn;
8151 const char *reason, *body = NULL;
8152 int ret, status;
8153
8154 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008155 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008156 hlua_pusherror(L, "txn object is not an HTTP transaction.");
8157 WILL_LJMP(lua_error(L));
8158 }
8159
8160 /* Default value */
8161 status = 200;
8162 reason = http_get_reason(status);
8163
8164 if (lua_istable(L, 2)) {
8165 /* load status and reason from the table argument at index 2 */
8166 ret = lua_getfield(L, 2, "status");
8167 if (ret == LUA_TNIL)
8168 goto reason;
8169 else if (ret != LUA_TNUMBER) {
8170 /* invalid status: ignore the reason */
8171 goto body;
8172 }
8173 status = lua_tointeger(L, -1);
8174
8175 reason:
8176 lua_pop(L, 1); /* restore the stack: remove status */
8177 ret = lua_getfield(L, 2, "reason");
8178 if (ret == LUA_TSTRING)
8179 reason = lua_tostring(L, -1);
8180
8181 body:
8182 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
8183 ret = lua_getfield(L, 2, "body");
8184 if (ret == LUA_TSTRING)
8185 body = lua_tostring(L, -1);
8186 lua_pop(L, 1); /* restore the stack: remove body */
8187 }
8188
8189 /* Create the Reply table */
8190 lua_newtable(L);
8191
8192 /* Add status element */
8193 lua_pushstring(L, "status");
8194 lua_pushinteger(L, status);
8195 lua_settable(L, -3);
8196
8197 /* Add reason element */
8198 reason = http_get_reason(status);
8199 lua_pushstring(L, "reason");
8200 lua_pushstring(L, reason);
8201 lua_settable(L, -3);
8202
8203 /* Add body element, nil if undefined */
8204 lua_pushstring(L, "body");
8205 if (body)
8206 lua_pushstring(L, body);
8207 else
8208 lua_pushnil(L);
8209 lua_settable(L, -3);
8210
8211 /* Add headers element */
8212 lua_pushstring(L, "headers");
8213 lua_newtable(L);
8214
8215 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8216 if (lua_istable(L, 2)) {
8217 /* load headers from the table argument at index 2. If it is a table, copy it. */
8218 ret = lua_getfield(L, 2, "headers");
8219 if (ret == LUA_TTABLE) {
8220 /* stack: [ ... <headers:table>, <table> ] */
8221 lua_pushnil(L);
8222 while (lua_next(L, -2) != 0) {
8223 /* stack: [ ... <headers:table>, <table>, k, v] */
8224 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
8225 /* invalid value type, skip it */
8226 lua_pop(L, 1);
8227 continue;
8228 }
8229
8230
8231 /* Duplicate the key and swap it with the value. */
8232 lua_pushvalue(L, -2);
8233 lua_insert(L, -2);
8234 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
8235
8236 lua_newtable(L);
8237 lua_insert(L, -2);
8238 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
8239
8240 if (lua_isstring(L, -1)) {
8241 /* push the value in the inner table */
8242 lua_rawseti(L, -2, 1);
8243 }
8244 else { /* table */
8245 lua_pushnil(L);
8246 while (lua_next(L, -2) != 0) {
8247 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
8248 if (!lua_isstring(L, -1)) {
8249 /* invalid value type, skip it*/
8250 lua_pop(L, 1);
8251 continue;
8252 }
8253 /* push the value in the inner table */
8254 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
8255 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
8256 }
8257 lua_pop(L, 1);
8258 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
8259 }
8260
8261 /* push (k,v) on the stack in the headers table:
8262 * stack: [ ... <headers:table>, <table>, k, k, v ]
8263 */
8264 lua_settable(L, -5);
8265 /* stack: [ ... <headers:table>, <table>, k ] */
8266 }
8267 }
8268 lua_pop(L, 1);
8269 }
8270 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8271 lua_settable(L, -3);
8272 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
8273
8274 /* Pop a class sesison metatable and affect it to the userdata. */
8275 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
8276 lua_setmetatable(L, -2);
8277 return 1;
8278}
8279
8280/* Set the reply status code, and optionally the reason. If no reason is
8281 * provided, the default one corresponding to the status code is used.
8282 */
8283__LJMP static int hlua_txn_reply_set_status(lua_State *L)
8284{
8285 int status = MAY_LJMP(luaL_checkinteger(L, 2));
8286 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
8287
8288 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008289 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008290
8291 if (status < 100 || status > 599) {
8292 lua_pushboolean(L, 0);
8293 return 1;
8294 }
8295 if (!reason)
8296 reason = http_get_reason(status);
8297
8298 lua_pushinteger(L, status);
8299 lua_setfield(L, 1, "status");
8300
8301 lua_pushstring(L, reason);
8302 lua_setfield(L, 1, "reason");
8303
8304 lua_pushboolean(L, 1);
8305 return 1;
8306}
8307
8308/* Add a header into the reply object. Each header name is associated to an
8309 * array of values in the "headers" table. If the header name is not found, a
8310 * new entry is created.
8311 */
8312__LJMP static int hlua_txn_reply_add_header(lua_State *L)
8313{
8314 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8315 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
8316 int ret;
8317
8318 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008319 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008320
8321 /* Push in the stack the "headers" entry. */
8322 ret = lua_getfield(L, 1, "headers");
8323 if (ret != LUA_TTABLE) {
8324 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
8325 WILL_LJMP(lua_error(L));
8326 }
8327
8328 /* check if the header is already registered. If not, register it. */
8329 ret = lua_getfield(L, -1, name);
8330 if (ret == LUA_TNIL) {
8331 /* Entry not found. */
8332 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
8333
8334 /* Insert the new header name in the array in the top of the stack.
8335 * It left the new array in the top of the stack.
8336 */
8337 lua_newtable(L);
8338 lua_pushstring(L, name);
8339 lua_pushvalue(L, -2);
8340 lua_settable(L, -4);
8341 }
8342 else if (ret != LUA_TTABLE) {
8343 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
8344 WILL_LJMP(lua_error(L));
8345 }
8346
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008347 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01008348 * the header value as new entry.
8349 */
8350 lua_pushstring(L, value);
8351 ret = lua_rawlen(L, -2);
8352 lua_rawseti(L, -2, ret + 1);
8353
8354 lua_pushboolean(L, 1);
8355 return 1;
8356}
8357
8358/* Remove all occurrences of a given header name. */
8359__LJMP static int hlua_txn_reply_del_header(lua_State *L)
8360{
8361 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8362 int ret;
8363
8364 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008365 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008366
8367 /* Push in the stack the "headers" entry. */
8368 ret = lua_getfield(L, 1, "headers");
8369 if (ret != LUA_TTABLE) {
8370 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
8371 WILL_LJMP(lua_error(L));
8372 }
8373
8374 lua_pushstring(L, name);
8375 lua_pushnil(L);
8376 lua_settable(L, -3);
8377
8378 lua_pushboolean(L, 1);
8379 return 1;
8380}
8381
8382/* Set the reply's body. Overwrite any existing entry. */
8383__LJMP static int hlua_txn_reply_set_body(lua_State *L)
8384{
8385 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
8386
8387 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008388 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008389
8390 lua_pushstring(L, payload);
8391 lua_setfield(L, 1, "body");
8392
8393 lua_pushboolean(L, 1);
8394 return 1;
8395}
8396
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008397__LJMP static int hlua_log(lua_State *L)
8398{
8399 int level;
8400 const char *msg;
8401
8402 MAY_LJMP(check_args(L, 2, "log"));
8403 level = MAY_LJMP(luaL_checkinteger(L, 1));
8404 msg = MAY_LJMP(luaL_checkstring(L, 2));
8405
8406 if (level < 0 || level >= NB_LOG_LEVELS)
8407 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
8408
8409 hlua_sendlog(NULL, level, msg);
8410 return 0;
8411}
8412
8413__LJMP static int hlua_log_debug(lua_State *L)
8414{
8415 const char *msg;
8416
8417 MAY_LJMP(check_args(L, 1, "debug"));
8418 msg = MAY_LJMP(luaL_checkstring(L, 1));
8419 hlua_sendlog(NULL, LOG_DEBUG, msg);
8420 return 0;
8421}
8422
8423__LJMP static int hlua_log_info(lua_State *L)
8424{
8425 const char *msg;
8426
8427 MAY_LJMP(check_args(L, 1, "info"));
8428 msg = MAY_LJMP(luaL_checkstring(L, 1));
8429 hlua_sendlog(NULL, LOG_INFO, msg);
8430 return 0;
8431}
8432
8433__LJMP static int hlua_log_warning(lua_State *L)
8434{
8435 const char *msg;
8436
8437 MAY_LJMP(check_args(L, 1, "warning"));
8438 msg = MAY_LJMP(luaL_checkstring(L, 1));
8439 hlua_sendlog(NULL, LOG_WARNING, msg);
8440 return 0;
8441}
8442
8443__LJMP static int hlua_log_alert(lua_State *L)
8444{
8445 const char *msg;
8446
8447 MAY_LJMP(check_args(L, 1, "alert"));
8448 msg = MAY_LJMP(luaL_checkstring(L, 1));
8449 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008450 return 0;
8451}
8452
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008453__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008454{
8455 int wakeup_ms = lua_tointeger(L, -1);
Willy Tarreau12c02702021-09-30 16:12:31 +02008456 if (!tick_is_expired(wakeup_ms, now_ms))
Willy Tarreau9635e032018-10-16 17:52:55 +02008457 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008458 return 0;
8459}
8460
8461__LJMP static int hlua_sleep(lua_State *L)
8462{
8463 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008464 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008465
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008466 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008467
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008468 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008469 wakeup_ms = tick_add(now_ms, delay);
8470 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008471
Willy Tarreau9635e032018-10-16 17:52:55 +02008472 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008473 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008474}
8475
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008476__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008477{
8478 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008479 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008480
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008481 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008482
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008483 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008484 wakeup_ms = tick_add(now_ms, delay);
8485 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008486
Willy Tarreau9635e032018-10-16 17:52:55 +02008487 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008488 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008489}
8490
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008491/* This functionis an LUA binding. it permits to give back
8492 * the hand at the HAProxy scheduler. It is used when the
8493 * LUA processing consumes a lot of time.
8494 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008495__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008496{
8497 return 0;
8498}
8499
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008500__LJMP static int hlua_yield(lua_State *L)
8501{
Willy Tarreau9635e032018-10-16 17:52:55 +02008502 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008503 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008504}
8505
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008506/* This function change the nice of the currently executed
8507 * task. It is used set low or high priority at the current
8508 * task.
8509 */
Willy Tarreau59551662015-03-10 14:23:13 +01008510__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008511{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008512 struct hlua *hlua;
8513 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008514
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008515 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008516 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008517
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008518 /* Get hlua struct, or NULL if we execute from main lua state */
8519 hlua = hlua_gethlua(L);
8520
8521 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008522 if (!hlua || !hlua->task)
8523 return 0;
8524
8525 if (nice < -1024)
8526 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008527 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008528 nice = 1024;
8529
8530 hlua->task->nice = nice;
8531 return 0;
8532}
8533
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008534/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008535 * HAProxy task subsystem when the task is awaked. The LUA runtime can
8536 * return an E_AGAIN signal, the emmiter of this signal must set a
8537 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008538 *
8539 * Task wrapper are longjmp safe because the only one Lua code
8540 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008541 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01008542struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008543{
Olivier Houchard9f6af332018-05-25 14:04:04 +02008544 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008545 enum hlua_exec status;
8546
Willy Tarreau6ef52f42022-06-15 14:19:48 +02008547 if (task->tid < 0)
8548 task->tid = tid;
8549
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008550 /* If it is the first call to the task, we must initialize the
8551 * execution timeouts.
8552 */
8553 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02008554 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008555
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008556 /* Execute the Lua code. */
8557 status = hlua_ctx_resume(hlua, 1);
8558
8559 switch (status) {
8560 /* finished or yield */
8561 case HLUA_E_OK:
8562 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008563 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02008564 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008565 break;
8566
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01008567 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01008568 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02008569 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008570 break;
8571
8572 /* finished with error. */
8573 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008574 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008575 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008576 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02008577 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008578 break;
8579
8580 case HLUA_E_ERR:
8581 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008582 SEND_ERR(NULL, "Lua task: unknown error.\n");
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008583 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008584 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02008585 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008586 break;
8587 }
Emeric Brun253e53e2017-10-17 18:58:40 +02008588 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008589}
8590
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008591/* This function is an LUA binding that register LUA function to be
8592 * executed after the HAProxy configuration parsing and before the
8593 * HAProxy scheduler starts. This function expect only one LUA
8594 * argument that is a function. This function returns nothing, but
8595 * throws if an error is encountered.
8596 */
8597__LJMP static int hlua_register_init(lua_State *L)
8598{
8599 struct hlua_init_function *init;
8600 int ref;
8601
8602 MAY_LJMP(check_args(L, 1, "register_init"));
8603
8604 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8605
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008606 init = calloc(1, sizeof(*init));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008607 if (!init)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008608 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008609
8610 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02008611 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008612 return 0;
8613}
8614
Ilya Shipitsin6f86eaa2022-11-30 16:22:42 +05008615/* This function is an LUA binding. It permits to register a task
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008616 * executed in parallel of the main HAroxy activity. The task is
8617 * created and it is set in the HAProxy scheduler. It can be called
8618 * from the "init" section, "post init" or during the runtime.
8619 *
8620 * Lua prototype:
8621 *
8622 * <none> core.register_task(<function>)
8623 */
8624static int hlua_register_task(lua_State *L)
8625{
Christopher Faulet5294ec02021-04-12 12:24:47 +02008626 struct hlua *hlua = NULL;
8627 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008628 int ref;
Thierry Fournier021d9862020-11-28 23:42:03 +01008629 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008630
8631 MAY_LJMP(check_args(L, 1, "register_task"));
8632
8633 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8634
Thierry Fournier75fc0292020-11-28 13:18:56 +01008635 /* Get the reference state. If the reference is NULL, L is the master
8636 * state, otherwise hlua->T is.
8637 */
8638 hlua = hlua_gethlua(L);
8639 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01008640 /* we are in runtime processing */
8641 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008642 else
Thierry Fournier021d9862020-11-28 23:42:03 +01008643 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01008644 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008645
Willy Tarreaubafbe012017-11-24 17:34:44 +01008646 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008647 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008648 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008649 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008650
Thierry Fournier59f11be2020-11-29 00:37:41 +01008651 /* We are in the common lua state, execute the task anywhere,
8652 * otherwise, inherit the current thread identifier
8653 */
8654 if (state_id == 0)
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008655 task = task_new_anywhere();
Thierry Fournier59f11be2020-11-29 00:37:41 +01008656 else
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008657 task = task_new_here();
Willy Tarreaue09101e2018-10-16 17:37:12 +02008658 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008659 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02008660
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008661 task->context = hlua;
8662 task->process = hlua_process_task;
8663
Thierry Fournier021d9862020-11-28 23:42:03 +01008664 if (!hlua_ctx_init(hlua, state_id, task, 1))
Christopher Faulet5294ec02021-04-12 12:24:47 +02008665 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008666
8667 /* Restore the function in the stack. */
8668 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref);
8669 hlua->nargs = 0;
8670
8671 /* Schedule task. */
Willy Tarreaue3957f82021-09-30 16:17:37 +02008672 task_wakeup(task, TASK_WOKEN_INIT);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008673
8674 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02008675
8676 alloc_error:
8677 task_destroy(task);
8678 hlua_ctx_destroy(hlua);
8679 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8680 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008681}
8682
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008683/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
8684 * doesn't allow "yield" functions because the HAProxy engine cannot
8685 * resume converters.
8686 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008687static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008688{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008689 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008690 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008691 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008692
Willy Tarreaube508f12016-03-10 11:47:01 +01008693 if (!stream)
8694 return 0;
8695
Willy Tarreau87b09662015-04-03 00:22:06 +02008696 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008697 * Lua context can be not initialized. This behavior
8698 * permits to save performances because a systematic
8699 * Lua initialization cause 5% performances loss.
8700 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008701 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008702 struct hlua *hlua;
8703
8704 hlua = pool_alloc(pool_head_hlua);
8705 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008706 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
8707 return 0;
8708 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008709 HLUA_INIT(hlua);
8710 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01008711 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008712 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
8713 return 0;
8714 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008715 }
8716
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008717 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008718 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008719
8720 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008721 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008722 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
8723 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01008724 else
8725 error = "critical error";
8726 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008727 return 0;
8728 }
8729
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008730 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008731 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008732 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008733 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008734 return 0;
8735 }
8736
8737 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01008738 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008739
8740 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008741 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008742 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008743 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008744 return 0;
8745 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008746 hlua_smp2lua(stream->hlua->T, smp);
8747 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008748
8749 /* push keywords in the stack. */
8750 if (arg_p) {
8751 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008752 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008753 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008754 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008755 return 0;
8756 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008757 hlua_arg2lua(stream->hlua->T, arg_p);
8758 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008759 }
8760 }
8761
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008762 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008763 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008764
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008765 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008766 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008767 }
8768
8769 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008770 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008771 /* finished. */
8772 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02008773 /* If the stack is empty, the function fails. */
8774 if (lua_gettop(stream->hlua->T) <= 0)
8775 return 0;
8776
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008777 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008778 hlua_lua2smp(stream->hlua->T, -1, smp);
8779 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008780 return 1;
8781
8782 /* yield. */
8783 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008784 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008785 return 0;
8786
8787 /* finished with error. */
8788 case HLUA_E_ERRMSG:
8789 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008790 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008791 fcn->name, lua_tostring(stream->hlua->T, -1));
8792 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008793 return 0;
8794
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008795 case HLUA_E_ETMOUT:
8796 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
8797 return 0;
8798
8799 case HLUA_E_NOMEM:
8800 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
8801 return 0;
8802
8803 case HLUA_E_YIELD:
8804 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
8805 return 0;
8806
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008807 case HLUA_E_ERR:
8808 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008809 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01008810 __fallthrough;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008811
8812 default:
8813 return 0;
8814 }
8815}
8816
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008817/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
8818 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01008819 * resume sample-fetches. This function will be called by the sample
8820 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008821 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02008822static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
8823 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008824{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008825 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008826 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008827 const char *error;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02008828 unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008829
Willy Tarreaube508f12016-03-10 11:47:01 +01008830 if (!stream)
8831 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01008832
Willy Tarreau87b09662015-04-03 00:22:06 +02008833 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008834 * Lua context can be not initialized. This behavior
8835 * permits to save performances because a systematic
8836 * Lua initialization cause 5% performances loss.
8837 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008838 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008839 struct hlua *hlua;
8840
8841 hlua = pool_alloc(pool_head_hlua);
8842 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008843 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
8844 return 0;
8845 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008846 hlua->T = NULL;
8847 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01008848 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008849 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
8850 return 0;
8851 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008852 }
8853
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008854 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008855 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008856
8857 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008858 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008859 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
8860 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01008861 else
8862 error = "critical error";
8863 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008864 return 0;
8865 }
8866
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008867 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008868 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008869 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008870 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008871 return 0;
8872 }
8873
8874 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01008875 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008876
8877 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02008878 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008879 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008880 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008881 return 0;
8882 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008883 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008884
8885 /* push keywords in the stack. */
8886 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
8887 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008888 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008889 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008890 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008891 return 0;
8892 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008893 hlua_arg2lua(stream->hlua->T, arg_p);
8894 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008895 }
8896
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008897 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008898 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008899
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008900 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008901 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008902 }
8903
8904 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008905 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008906 /* finished. */
8907 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02008908 /* If the stack is empty, the function fails. */
8909 if (lua_gettop(stream->hlua->T) <= 0)
8910 return 0;
8911
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008912 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008913 hlua_lua2smp(stream->hlua->T, -1, smp);
8914 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008915
8916 /* Set the end of execution flag. */
8917 smp->flags &= ~SMP_F_MAY_CHANGE;
8918 return 1;
8919
8920 /* yield. */
8921 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008922 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008923 return 0;
8924
8925 /* finished with error. */
8926 case HLUA_E_ERRMSG:
8927 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008928 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008929 fcn->name, lua_tostring(stream->hlua->T, -1));
8930 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008931 return 0;
8932
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008933 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008934 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
8935 return 0;
8936
8937 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008938 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
8939 return 0;
8940
8941 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008942 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
8943 return 0;
8944
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008945 case HLUA_E_ERR:
8946 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008947 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01008948 __fallthrough;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008949
8950 default:
8951 return 0;
8952 }
8953}
8954
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008955/* This function is an LUA binding used for registering
8956 * "sample-conv" functions. It expects a converter name used
8957 * in the haproxy configuration file, and an LUA function.
8958 */
8959__LJMP static int hlua_register_converters(lua_State *L)
8960{
8961 struct sample_conv_kw_list *sck;
8962 const char *name;
8963 int ref;
8964 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02008965 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008966 struct sample_conv *sc;
8967 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008968
8969 MAY_LJMP(check_args(L, 2, "register_converters"));
8970
8971 /* First argument : converter name. */
8972 name = MAY_LJMP(luaL_checkstring(L, 1));
8973
8974 /* Second argument : lua function. */
8975 ref = MAY_LJMP(hlua_checkfunction(L, 2));
8976
Thierry Fournierf67442e2020-11-28 20:41:07 +01008977 /* Check if the converter is already registered */
8978 trash = get_trash_chunk();
8979 chunk_printf(trash, "lua.%s", name);
8980 sc = find_sample_conv(trash->area, trash->data);
8981 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008982 fcn = sc->private;
8983 if (fcn->function_ref[hlua_state_id] != -1) {
8984 ha_warning("Trying to register converter 'lua.%s' more than once. "
8985 "This will become a hard error in version 2.5.\n", name);
8986 }
8987 fcn->function_ref[hlua_state_id] = ref;
8988 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008989 }
8990
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008991 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008992 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008993 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +02008994 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008995 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008996 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +02008997 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008998
8999 /* Fill fcn. */
9000 fcn->name = strdup(name);
9001 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +02009002 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009003 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009004
9005 /* List head */
9006 sck->list.n = sck->list.p = NULL;
9007
9008 /* converter keyword. */
9009 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009010 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009011 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +02009012 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009013
9014 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
9015 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01009016 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 +01009017 sck->kw[0].val_args = NULL;
9018 sck->kw[0].in_type = SMP_T_STR;
9019 sck->kw[0].out_type = SMP_T_STR;
9020 sck->kw[0].private = fcn;
9021
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009022 /* Register this new converter */
9023 sample_register_convs(sck);
9024
9025 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +02009026
9027 alloc_error:
9028 release_hlua_function(fcn);
9029 ha_free(&sck);
9030 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9031 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009032}
9033
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009034/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009035 * "sample-fetch" functions. It expects a converter name used
9036 * in the haproxy configuration file, and an LUA function.
9037 */
9038__LJMP static int hlua_register_fetches(lua_State *L)
9039{
9040 const char *name;
9041 int ref;
9042 int len;
9043 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +02009044 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009045 struct sample_fetch *sf;
9046 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009047
9048 MAY_LJMP(check_args(L, 2, "register_fetches"));
9049
9050 /* First argument : sample-fetch name. */
9051 name = MAY_LJMP(luaL_checkstring(L, 1));
9052
9053 /* Second argument : lua function. */
9054 ref = MAY_LJMP(hlua_checkfunction(L, 2));
9055
Thierry Fournierf67442e2020-11-28 20:41:07 +01009056 /* Check if the sample-fetch is already registered */
9057 trash = get_trash_chunk();
9058 chunk_printf(trash, "lua.%s", name);
9059 sf = find_sample_fetch(trash->area, trash->data);
9060 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01009061 fcn = sf->private;
9062 if (fcn->function_ref[hlua_state_id] != -1) {
9063 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
9064 "This will become a hard error in version 2.5.\n", name);
9065 }
9066 fcn->function_ref[hlua_state_id] = ref;
9067 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009068 }
9069
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009070 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009071 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009072 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +02009073 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01009074 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009075 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +02009076 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009077
9078 /* Fill fcn. */
9079 fcn->name = strdup(name);
9080 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +02009081 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009082 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009083
9084 /* List head */
9085 sfk->list.n = sfk->list.p = NULL;
9086
9087 /* sample-fetch keyword. */
9088 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009089 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009090 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +02009091 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009092
9093 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
9094 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01009095 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 +01009096 sfk->kw[0].val_args = NULL;
9097 sfk->kw[0].out_type = SMP_T_STR;
9098 sfk->kw[0].use = SMP_USE_HTTP_ANY;
9099 sfk->kw[0].val = 0;
9100 sfk->kw[0].private = fcn;
9101
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009102 /* Register this new fetch. */
9103 sample_register_fetches(sfk);
9104
9105 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +02009106
9107 alloc_error:
9108 release_hlua_function(fcn);
9109 ha_free(&sfk);
9110 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9111 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009112}
9113
Christopher Faulet501465d2020-02-26 14:54:16 +01009114/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009115 */
Christopher Faulet501465d2020-02-26 14:54:16 +01009116__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009117{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009118 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009119 unsigned int delay;
9120 unsigned int wakeup_ms;
9121
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009122 /* Get hlua struct, or NULL if we execute from main lua state */
9123 hlua = hlua_gethlua(L);
9124 if (!hlua) {
9125 return 0;
9126 }
9127
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009128 MAY_LJMP(check_args(L, 1, "wake_time"));
9129
9130 delay = MAY_LJMP(luaL_checkinteger(L, 1));
9131 wakeup_ms = tick_add(now_ms, delay);
9132 hlua->wake_time = wakeup_ms;
9133 return 0;
9134}
9135
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009136/* This function is a wrapper to execute each LUA function declared as an action
9137 * wrapper during the initialisation period. This function may return any
9138 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
9139 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
9140 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009141 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009142static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02009143 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009144{
9145 char **arg;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02009146 unsigned int hflags = HLUA_TXN_ACT_CTX;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009147 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009148 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009149
9150 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01009151 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
9152 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
9153 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
9154 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009155 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009156 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009157 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009158 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009159
Willy Tarreau87b09662015-04-03 00:22:06 +02009160 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009161 * Lua context can be not initialized. This behavior
9162 * permits to save performances because a systematic
9163 * Lua initialization cause 5% performances loss.
9164 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009165 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009166 struct hlua *hlua;
9167
9168 hlua = pool_alloc(pool_head_hlua);
9169 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009170 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009171 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009172 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009173 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009174 HLUA_INIT(hlua);
9175 s->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01009176 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 +01009177 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009178 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009179 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009180 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009181 }
9182
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009183 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009184 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009185
9186 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009187 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009188 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
9189 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009190 else
9191 error = "critical error";
9192 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009193 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009194 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009195 }
9196
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009197 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009198 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009199 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009200 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009201 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009202 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009203 }
9204
9205 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01009206 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 +01009207
Willy Tarreau87b09662015-04-03 00:22:06 +02009208 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02009209 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009210 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009211 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009212 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009213 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009214 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009215 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009216
9217 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009218 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009219 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009220 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009221 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009222 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009223 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009224 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009225 lua_pushstring(s->hlua->T, *arg);
9226 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009227 }
9228
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009229 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009230 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009231
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009232 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009233 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009234 }
9235
9236 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01009237 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009238 /* finished. */
9239 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009240 /* Catch the return value */
9241 if (lua_gettop(s->hlua->T) > 0)
9242 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009243
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009244 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02009245 if (act_ret == ACT_RET_YIELD) {
9246 if (flags & ACT_OPT_FINAL)
9247 goto err_yield;
9248
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009249 if (dir == SMP_OPT_DIR_REQ)
9250 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
9251 s->hlua->wake_time);
9252 else
9253 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
9254 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009255 }
9256 goto end;
9257
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009258 /* yield. */
9259 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01009260 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009261 if (dir == SMP_OPT_DIR_REQ)
9262 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
9263 s->hlua->wake_time);
9264 else
9265 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
9266 s->hlua->wake_time);
9267
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009268 /* Some actions can be wake up when a "write" event
9269 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009270 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009271 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02009272 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009273 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009274 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009275 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009276 act_ret = ACT_RET_YIELD;
9277 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009278
9279 /* finished with error. */
9280 case HLUA_E_ERRMSG:
9281 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009282 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009283 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009284 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009285 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009286
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009287 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +01009288 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009289 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009290
9291 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +01009292 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009293 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009294
9295 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02009296 err_yield:
9297 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009298 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009299 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009300 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009301
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009302 case HLUA_E_ERR:
9303 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009304 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009305 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009306
9307 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009308 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009309 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009310
9311 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02009312 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009313 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009314 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009315}
9316
Willy Tarreau144f84a2021-03-02 16:09:26 +01009317struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009318{
Olivier Houchard9f6af332018-05-25 14:04:04 +02009319 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009320
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009321 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02009322 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02009323 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009324}
9325
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009326static int hlua_applet_tcp_init(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009327{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009328 struct hlua_tcp_ctx *tcp_ctx = applet_reserve_svcctx(ctx, sizeof(*tcp_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +02009329 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009330 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009331 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009332 struct task *task;
9333 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009334 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009335
Willy Tarreaubafbe012017-11-24 17:34:44 +01009336 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009337 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009338 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009339 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009340 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009341 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009342 HLUA_INIT(hlua);
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009343 tcp_ctx->hlua = hlua;
9344 tcp_ctx->flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009345
9346 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +02009347 task = task_new_here();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009348 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009349 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009350 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009351 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009352 }
9353 task->nice = 0;
9354 task->context = ctx;
9355 task->process = hlua_applet_wakeup;
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009356 tcp_ctx->task = task;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009357
9358 /* In the execution wrappers linked with a stream, the
9359 * Lua context can be not initialized. This behavior
9360 * permits to save performances because a systematic
9361 * Lua initialization cause 5% performances loss.
9362 */
Thierry Fournierc7492592020-11-28 23:57:24 +01009363 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 +01009364 SEND_ERR(strm->be, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009365 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009366 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009367 }
9368
9369 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02009370 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009371
9372 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009373 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01009374 if (lua_type(hlua->T, -1) == LUA_TSTRING)
9375 error = lua_tostring(hlua->T, -1);
9376 else
9377 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009378 SEND_ERR(strm->be, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009379 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +02009380 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009381 }
9382
9383 /* Check stack available size. */
9384 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009385 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009386 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009387 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009388 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009389 }
9390
9391 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01009392 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009393
9394 /* Create and and push object stream in the stack. */
9395 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009396 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009397 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009398 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009399 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009400 }
9401 hlua->nargs = 1;
9402
9403 /* push keywords in the stack. */
9404 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
9405 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009406 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009407 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009408 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009409 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009410 }
9411 lua_pushstring(hlua->T, *arg);
9412 hlua->nargs++;
9413 }
9414
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009415 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009416
9417 /* Wakeup the applet ASAP. */
Willy Tarreau90e8b452022-05-25 18:21:43 +02009418 applet_need_more_data(ctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02009419 applet_have_more_data(ctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009420
Christopher Fauletc9929382022-05-12 11:52:27 +02009421 return 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009422}
9423
Willy Tarreau60409db2019-08-21 14:14:50 +02009424void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009425{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009426 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02009427 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009428 struct stream *strm = __sc_strm(sc);
9429 struct channel *res = sc_ic(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009430 struct act_rule *rule = ctx->rule;
9431 struct proxy *px = strm->be;
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009432 struct hlua *hlua = tcp_ctx->hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009433
9434 /* The applet execution is already done. */
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009435 if (tcp_ctx->flags & APPLET_DONE) {
Olivier Houchard594c8c52018-08-28 14:41:31 +02009436 /* eat the whole request */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009437 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009438 return;
Olivier Houchard594c8c52018-08-28 14:41:31 +02009439 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009440
9441 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009442 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009443 return;
9444
9445 /* Execute the function. */
9446 switch (hlua_ctx_resume(hlua, 1)) {
9447 /* finished. */
9448 case HLUA_E_OK:
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009449 tcp_ctx->flags |= APPLET_DONE;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009450
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009451 /* eat the whole request */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009452 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
Christopher Faulet6e1bbc42022-12-12 08:08:15 +01009453 res->flags |= CF_READ_EVENT;
Willy Tarreau3e7be362022-05-27 10:35:27 +02009454 sc_shutr(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009455 return;
9456
9457 /* yield. */
9458 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01009459 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009460 task_schedule(tcp_ctx->task, hlua->wake_time);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009461 return;
9462
9463 /* finished with error. */
9464 case HLUA_E_ERRMSG:
9465 /* Display log. */
9466 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009467 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009468 lua_pop(hlua->T, 1);
9469 goto error;
9470
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009471 case HLUA_E_ETMOUT:
9472 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009473 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009474 goto error;
9475
9476 case HLUA_E_NOMEM:
9477 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009478 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009479 goto error;
9480
9481 case HLUA_E_YIELD: /* unexpected */
9482 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009483 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009484 goto error;
9485
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009486 case HLUA_E_ERR:
9487 /* Display log. */
9488 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009489 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009490 goto error;
9491
9492 default:
9493 goto error;
9494 }
9495
9496error:
9497
9498 /* For all other cases, just close the stream. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009499 sc_shutw(sc);
9500 sc_shutr(sc);
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009501 tcp_ctx->flags |= APPLET_DONE;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009502}
9503
9504static void hlua_applet_tcp_release(struct appctx *ctx)
9505{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009506 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
9507
9508 task_destroy(tcp_ctx->task);
9509 tcp_ctx->task = NULL;
9510 hlua_ctx_destroy(tcp_ctx->hlua);
9511 tcp_ctx->hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009512}
9513
Christopher Fauletc9929382022-05-12 11:52:27 +02009514/* The function returns 0 if the initialisation is complete or -1 if
9515 * an errors occurs. It also reserves the appctx for an hlua_http_ctx.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009516 */
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009517static int hlua_applet_http_init(struct appctx *ctx)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009518{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009519 struct hlua_http_ctx *http_ctx = applet_reserve_svcctx(ctx, sizeof(*http_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +02009520 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009521 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009522 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009523 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009524 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009525 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009526 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009527
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009528 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01009529 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009530 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009531 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009532 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009533 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009534 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009535 HLUA_INIT(hlua);
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009536 http_ctx->hlua = hlua;
9537 http_ctx->left_bytes = -1;
9538 http_ctx->flags = 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009539
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01009540 if (txn->req.flags & HTTP_MSGF_VER_11)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009541 http_ctx->flags |= APPLET_HTTP11;
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01009542
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009543 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +02009544 task = task_new_here();
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009545 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009546 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009547 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009548 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009549 }
9550 task->nice = 0;
9551 task->context = ctx;
9552 task->process = hlua_applet_wakeup;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009553 http_ctx->task = task;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009554
9555 /* In the execution wrappers linked with a stream, the
9556 * Lua context can be not initialized. This behavior
9557 * permits to save performances because a systematic
9558 * Lua initialization cause 5% performances loss.
9559 */
Thierry Fournierc7492592020-11-28 23:57:24 +01009560 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 +01009561 SEND_ERR(strm->be, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009562 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009563 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009564 }
9565
9566 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02009567 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009568
9569 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009570 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01009571 if (lua_type(hlua->T, -1) == LUA_TSTRING)
9572 error = lua_tostring(hlua->T, -1);
9573 else
9574 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009575 SEND_ERR(strm->be, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009576 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +02009577 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009578 }
9579
9580 /* Check stack available size. */
9581 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009582 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009583 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009584 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009585 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009586 }
9587
9588 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01009589 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009590
9591 /* Create and and push object stream in the stack. */
9592 if (!hlua_applet_http_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009593 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009594 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009595 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009596 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009597 }
9598 hlua->nargs = 1;
9599
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009600 /* push keywords in the stack. */
9601 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
9602 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009603 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009604 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009605 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009606 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009607 }
9608 lua_pushstring(hlua->T, *arg);
9609 hlua->nargs++;
9610 }
9611
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009612 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009613
9614 /* Wakeup the applet when data is ready for read. */
Willy Tarreau90e8b452022-05-25 18:21:43 +02009615 applet_need_more_data(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009616
Christopher Fauletc9929382022-05-12 11:52:27 +02009617 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009618}
9619
Willy Tarreau60409db2019-08-21 14:14:50 +02009620void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009621{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009622 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02009623 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009624 struct stream *strm = __sc_strm(sc);
9625 struct channel *req = sc_oc(sc);
9626 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009627 struct act_rule *rule = ctx->rule;
9628 struct proxy *px = strm->be;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009629 struct hlua *hlua = http_ctx->hlua;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009630 struct htx *req_htx, *res_htx;
9631
9632 res_htx = htx_from_buf(&res->buf);
9633
9634 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02009635 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009636 goto out;
9637
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009638 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009639 if (!b_size(&res->buf)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02009640 sc_need_room(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009641 goto out;
9642 }
9643 /* check that the output is not closed */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009644 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR))
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009645 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009646
9647 /* Set the currently running flag. */
9648 if (!HLUA_IS_RUNNING(hlua) &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009649 !(http_ctx->flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +02009650 if (!co_data(req)) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02009651 applet_need_more_data(ctx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009652 goto out;
9653 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009654 }
9655
9656 /* Executes The applet if it is not done. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009657 if (!(http_ctx->flags & APPLET_DONE)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009658
9659 /* Execute the function. */
9660 switch (hlua_ctx_resume(hlua, 1)) {
9661 /* finished. */
9662 case HLUA_E_OK:
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009663 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009664 break;
9665
9666 /* yield. */
9667 case HLUA_E_AGAIN:
9668 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009669 task_schedule(http_ctx->task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009670 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009671
9672 /* finished with error. */
9673 case HLUA_E_ERRMSG:
9674 /* Display log. */
9675 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009676 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009677 lua_pop(hlua->T, 1);
9678 goto error;
9679
9680 case HLUA_E_ETMOUT:
9681 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009682 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009683 goto error;
9684
9685 case HLUA_E_NOMEM:
9686 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009687 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009688 goto error;
9689
9690 case HLUA_E_YIELD: /* unexpected */
9691 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009692 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009693 goto error;
9694
9695 case HLUA_E_ERR:
9696 /* Display log. */
9697 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009698 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009699 goto error;
9700
9701 default:
9702 goto error;
9703 }
9704 }
9705
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009706 if (http_ctx->flags & APPLET_DONE) {
9707 if (http_ctx->flags & APPLET_RSP_SENT)
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009708 goto done;
9709
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009710 if (!(http_ctx->flags & APPLET_HDR_SENT))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009711 goto error;
9712
Christopher Fauletf89af9c2022-04-07 10:07:18 +02009713 /* no more data are expected. If the response buffer is empty
9714 * for a chunked message, be sure to add something (EOT block in
9715 * this case) to have something to send. It is important to be
9716 * sure the EOM flags will be handled by the endpoint.
9717 */
9718 if (htx_is_empty(res_htx) && (strm->txn->rsp.flags & (HTTP_MSGF_XFER_LEN|HTTP_MSGF_CNT_LEN)) == HTTP_MSGF_XFER_LEN) {
9719 if (!htx_add_endof(res_htx, HTX_BLK_EOT)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02009720 sc_need_room(sc);
Christopher Fauletf89af9c2022-04-07 10:07:18 +02009721 goto out;
9722 }
9723 channel_add_input(res, 1);
9724 }
9725
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01009726 res_htx->flags |= HTX_FL_EOM;
Christopher Fauletd8d27082022-03-07 15:50:54 +01009727 res->flags |= CF_EOI;
Willy Tarreaud869e132022-05-17 18:05:31 +02009728 se_fl_set(ctx->sedesc, SE_FL_EOI);
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009729 strm->txn->status = http_ctx->status;
9730 http_ctx->flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009731 }
9732
9733 done:
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009734 if (http_ctx->flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009735 if (!(res->flags & CF_SHUTR)) {
Christopher Faulet6e1bbc42022-12-12 08:08:15 +01009736 res->flags |= CF_READ_EVENT;
Willy Tarreau3e7be362022-05-27 10:35:27 +02009737 sc_shutr(sc);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009738 }
9739
9740 /* eat the whole request */
9741 if (co_data(req)) {
9742 req_htx = htx_from_buf(&req->buf);
9743 co_htx_skip(req, req_htx, co_data(req));
9744 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009745 }
9746 }
9747
9748 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009749 htx_to_buf(res_htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009750 return;
9751
9752 error:
9753
9754 /* If we are in HTTP mode, and we are not send any
9755 * data, return a 500 server error in best effort:
9756 * if there is no room available in the buffer,
9757 * just close the connection.
9758 */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009759 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02009760 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009761
9762 channel_erase(res);
9763 res->buf.data = b_data(err);
9764 memcpy(res->buf.area, b_head(err), b_data(err));
9765 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01009766 channel_add_input(res, res_htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009767 }
9768 if (!(strm->flags & SF_ERR_MASK))
9769 strm->flags |= SF_ERR_RESOURCE;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009770 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009771 goto done;
9772}
9773
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009774static void hlua_applet_http_release(struct appctx *ctx)
9775{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009776 struct hlua_http_ctx *http_ctx = ctx->svcctx;
9777
9778 task_destroy(http_ctx->task);
9779 http_ctx->task = NULL;
9780 hlua_ctx_destroy(http_ctx->hlua);
9781 http_ctx->hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009782}
9783
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009784/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009785 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009786 *
9787 * This function can fail with an abort() due to an Lua critical error.
9788 * We are in the configuration parsing process of HAProxy, this abort() is
9789 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009790 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009791static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
9792 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009793{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009794 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009795 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009796
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009797 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009798 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009799 if (!rule->arg.hlua_rule) {
9800 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009801 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009802 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009803
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009804 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02009805 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
9806 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009807 if (!rule->arg.hlua_rule->args) {
9808 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009809 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009810 }
9811
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009812 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01009813 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009814
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009815 /* Expect some arguments */
9816 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01009817 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009818 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +02009819 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009820 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01009821 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009822 if (!rule->arg.hlua_rule->args[i]) {
9823 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009824 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009825 }
9826 (*cur_arg)++;
9827 }
9828 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009829
Thierry FOURNIER42148732015-09-02 17:17:33 +02009830 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009831 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02009832 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +02009833
9834 error:
9835 if (rule->arg.hlua_rule) {
9836 if (rule->arg.hlua_rule->args) {
9837 for (i = 0; i < fcn->nargs; i++)
9838 ha_free(&rule->arg.hlua_rule->args[i]);
9839 ha_free(&rule->arg.hlua_rule->args);
9840 }
9841 ha_free(&rule->arg.hlua_rule);
9842 }
9843 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009844}
9845
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009846static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
9847 struct act_rule *rule, char **err)
9848{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009849 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009850
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009851 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009852 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009853 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009854 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009855 * the call of this analyzer.
9856 */
9857 if (rule->from != ACT_F_HTTP_REQ) {
9858 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
9859 return ACT_RET_PRS_ERR;
9860 }
9861
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009862 /* Memory for the rule. */
9863 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
9864 if (!rule->arg.hlua_rule) {
9865 memprintf(err, "out of memory error");
9866 return ACT_RET_PRS_ERR;
9867 }
9868
9869 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01009870 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009871
9872 /* TODO: later accept arguments. */
9873 rule->arg.hlua_rule->args = NULL;
9874
9875 /* Add applet pointer in the rule. */
9876 rule->applet.obj_type = OBJ_TYPE_APPLET;
9877 rule->applet.name = fcn->name;
9878 rule->applet.init = hlua_applet_http_init;
9879 rule->applet.fct = hlua_applet_http_fct;
9880 rule->applet.release = hlua_applet_http_release;
9881 rule->applet.timeout = hlua_timeout_applet;
9882
9883 return ACT_RET_PRS_OK;
9884}
9885
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009886/* This function is an LUA binding used for registering
9887 * "sample-conv" functions. It expects a converter name used
9888 * in the haproxy configuration file, and an LUA function.
9889 */
9890__LJMP static int hlua_register_action(lua_State *L)
9891{
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009892 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009893 const char *name;
9894 int ref;
9895 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009896 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009897 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009898 struct buffer *trash;
9899 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009900
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009901 /* Initialise the number of expected arguments at 0. */
9902 nargs = 0;
9903
9904 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
9905 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009906
9907 /* First argument : converter name. */
9908 name = MAY_LJMP(luaL_checkstring(L, 1));
9909
9910 /* Second argument : environment. */
9911 if (lua_type(L, 2) != LUA_TTABLE)
9912 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
9913
9914 /* Third argument : lua function. */
9915 ref = MAY_LJMP(hlua_checkfunction(L, 3));
9916
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009917 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009918 if (lua_gettop(L) >= 4)
9919 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
9920
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009921 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009922 lua_pushnil(L);
9923 while (lua_next(L, 2) != 0) {
9924 if (lua_type(L, -1) != LUA_TSTRING)
9925 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
9926
Thierry Fournierf67442e2020-11-28 20:41:07 +01009927 /* Check if action exists */
9928 trash = get_trash_chunk();
9929 chunk_printf(trash, "lua.%s", name);
9930 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
9931 akw = tcp_req_cont_action(trash->area);
9932 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
9933 akw = tcp_res_cont_action(trash->area);
9934 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
9935 akw = action_http_req_custom(trash->area);
9936 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
9937 akw = action_http_res_custom(trash->area);
9938 } else {
9939 akw = NULL;
9940 }
9941 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01009942 fcn = akw->private;
9943 if (fcn->function_ref[hlua_state_id] != -1) {
9944 ha_warning("Trying to register action 'lua.%s' more than once. "
9945 "This will become a hard error in version 2.5.\n", name);
9946 }
9947 fcn->function_ref[hlua_state_id] = ref;
9948
9949 /* pop the environment string. */
9950 lua_pop(L, 1);
9951 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009952 }
9953
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009954 /* Check required environment. Only accepted "http" or "tcp". */
9955 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009956 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009957 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009958 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01009959 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009960 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009961 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009962
9963 /* Fill fcn. */
9964 fcn->name = strdup(name);
9965 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009966 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009967 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009968
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07009969 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009970 fcn->nargs = nargs;
9971
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009972 /* List head */
9973 akl->list.n = akl->list.p = NULL;
9974
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009975 /* action keyword. */
9976 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009977 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009978 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009979 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009980
9981 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
9982
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02009983 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009984 akl->kw[0].private = fcn;
9985 akl->kw[0].parse = action_register_lua;
9986
9987 /* select the action registering point. */
9988 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
9989 tcp_req_cont_keywords_register(akl);
9990 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
9991 tcp_res_cont_keywords_register(akl);
9992 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
9993 http_req_keywords_register(akl);
9994 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
9995 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009996 else {
9997 release_hlua_function(fcn);
9998 if (akl)
9999 ha_free((char **)&(akl->kw[0].kw));
10000 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010010001 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010002 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
10003 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010004 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010005
10006 /* pop the environment string. */
10007 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010008
10009 /* reset for next loop */
10010 akl = NULL;
10011 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010012 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010013 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010014
10015 alloc_error:
10016 release_hlua_function(fcn);
10017 ha_free(&akl);
10018 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10019 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010020}
10021
10022static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
10023 struct act_rule *rule, char **err)
10024{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010025 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010026
Christopher Faulet280f85b2019-07-15 15:02:04 +020010027 if (px->mode == PR_MODE_HTTP) {
10028 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +010010029 return ACT_RET_PRS_ERR;
10030 }
10031
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010032 /* Memory for the rule. */
10033 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
10034 if (!rule->arg.hlua_rule) {
10035 memprintf(err, "out of memory error");
10036 return ACT_RET_PRS_ERR;
10037 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010038
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010039 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010040 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010041
10042 /* TODO: later accept arguments. */
10043 rule->arg.hlua_rule->args = NULL;
10044
10045 /* Add applet pointer in the rule. */
10046 rule->applet.obj_type = OBJ_TYPE_APPLET;
10047 rule->applet.name = fcn->name;
10048 rule->applet.init = hlua_applet_tcp_init;
10049 rule->applet.fct = hlua_applet_tcp_fct;
10050 rule->applet.release = hlua_applet_tcp_release;
10051 rule->applet.timeout = hlua_timeout_applet;
10052
10053 return 0;
10054}
10055
10056/* This function is an LUA binding used for registering
10057 * "sample-conv" functions. It expects a converter name used
10058 * in the haproxy configuration file, and an LUA function.
10059 */
10060__LJMP static int hlua_register_service(lua_State *L)
10061{
10062 struct action_kw_list *akl;
10063 const char *name;
10064 const char *env;
10065 int ref;
10066 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010067 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010068 struct buffer *trash;
10069 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010070
10071 MAY_LJMP(check_args(L, 3, "register_service"));
10072
10073 /* First argument : converter name. */
10074 name = MAY_LJMP(luaL_checkstring(L, 1));
10075
10076 /* Second argument : environment. */
10077 env = MAY_LJMP(luaL_checkstring(L, 2));
10078
10079 /* Third argument : lua function. */
10080 ref = MAY_LJMP(hlua_checkfunction(L, 3));
10081
Thierry Fournierf67442e2020-11-28 20:41:07 +010010082 /* Check for service already registered */
10083 trash = get_trash_chunk();
10084 chunk_printf(trash, "lua.%s", name);
10085 akw = service_find(trash->area);
10086 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010087 fcn = akw->private;
10088 if (fcn->function_ref[hlua_state_id] != -1) {
10089 ha_warning("Trying to register service 'lua.%s' more than once. "
10090 "This will become a hard error in version 2.5.\n", name);
10091 }
10092 fcn->function_ref[hlua_state_id] = ref;
10093 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010094 }
10095
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010096 /* Allocate and fill the sample fetch keyword struct. */
10097 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
10098 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010099 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010100 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010101 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010102 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010103
10104 /* Fill fcn. */
10105 len = strlen("<lua.>") + strlen(name) + 1;
10106 fcn->name = calloc(1, len);
10107 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010108 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010109 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +010010110 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010111
10112 /* List head */
10113 akl->list.n = akl->list.p = NULL;
10114
10115 /* converter keyword. */
10116 len = strlen("lua.") + strlen(name) + 1;
10117 akl->kw[0].kw = calloc(1, len);
10118 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010119 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010120
10121 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
10122
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +010010123 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010124 if (strcmp(env, "tcp") == 0)
10125 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010126 else if (strcmp(env, "http") == 0)
10127 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010128 else {
10129 release_hlua_function(fcn);
10130 if (akl)
10131 ha_free((char **)&(akl->kw[0].kw));
10132 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010010133 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +010010134 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +020010135 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010136
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020010137 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010138 akl->kw[0].private = fcn;
10139
10140 /* End of array. */
10141 memset(&akl->kw[1], 0, sizeof(*akl->kw));
10142
10143 /* Register this new converter */
10144 service_keywords_register(akl);
10145
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010146 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010147
10148 alloc_error:
10149 release_hlua_function(fcn);
10150 ha_free(&akl);
10151 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10152 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010153}
10154
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010155/* This function initialises Lua cli handler. It copies the
10156 * arguments in the Lua stack and create channel IO objects.
10157 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +020010158static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010159{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010160 struct hlua_cli_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010161 struct hlua *hlua;
10162 struct hlua_function *fcn;
10163 int i;
10164 const char *error;
10165
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010166 fcn = private;
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010167 ctx->fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010168
Willy Tarreaubafbe012017-11-24 17:34:44 +010010169 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010170 if (!hlua) {
10171 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010172 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010173 }
10174 HLUA_INIT(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010175 ctx->hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010176
10177 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +050010178 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010179 * applet_http. It is absolutely compatible.
10180 */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010181 ctx->task = task_new_here();
10182 if (!ctx->task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +010010183 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010184 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010185 }
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010186 ctx->task->nice = 0;
10187 ctx->task->context = appctx;
10188 ctx->task->process = hlua_applet_wakeup;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010189
10190 /* Initialises the Lua context */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010191 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), ctx->task, 0)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010192 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010193 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010194 }
10195
10196 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010197 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010198 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10199 error = lua_tostring(hlua->T, -1);
10200 else
10201 error = "critical error";
10202 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
10203 goto error;
10204 }
10205
10206 /* Check stack available size. */
10207 if (!lua_checkstack(hlua->T, 2)) {
10208 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10209 goto error;
10210 }
10211
10212 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +010010213 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010214
10215 /* Once the arguments parsed, the CLI is like an AppletTCP,
10216 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010217 */
10218 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
10219 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10220 goto error;
10221 }
10222 hlua->nargs = 1;
10223
10224 /* push keywords in the stack. */
10225 for (i = 0; *args[i]; i++) {
10226 /* Check stack available size. */
10227 if (!lua_checkstack(hlua->T, 1)) {
10228 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10229 goto error;
10230 }
10231 lua_pushstring(hlua->T, args[i]);
10232 hlua->nargs++;
10233 }
10234
10235 /* We must initialize the execution timeouts. */
10236 hlua->max_time = hlua_timeout_session;
10237
10238 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010239 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010240
10241 /* It's ok */
10242 return 0;
10243
10244 /* It's not ok. */
10245error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010246 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010247 hlua_ctx_destroy(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010248 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010249 return 1;
10250}
10251
10252static int hlua_cli_io_handler_fct(struct appctx *appctx)
10253{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010254 struct hlua_cli_ctx *ctx = appctx->svcctx;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010255 struct hlua *hlua;
Willy Tarreau475e4632022-05-27 10:26:46 +020010256 struct stconn *sc;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010257 struct hlua_function *fcn;
10258
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010259 hlua = ctx->hlua;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010260 sc = appctx_sc(appctx);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010261 fcn = ctx->fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010262
10263 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau475e4632022-05-27 10:26:46 +020010264 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010265 return 1;
10266
10267 /* Execute the function. */
10268 switch (hlua_ctx_resume(hlua, 1)) {
10269
10270 /* finished. */
10271 case HLUA_E_OK:
10272 return 1;
10273
10274 /* yield. */
10275 case HLUA_E_AGAIN:
10276 /* We want write. */
10277 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreau475e4632022-05-27 10:26:46 +020010278 sc_need_room(sc);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010279 /* Set the timeout. */
10280 if (hlua->wake_time != TICK_ETERNITY)
10281 task_schedule(hlua->task, hlua->wake_time);
10282 return 0;
10283
10284 /* finished with error. */
10285 case HLUA_E_ERRMSG:
10286 /* Display log. */
10287 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
10288 fcn->name, lua_tostring(hlua->T, -1));
10289 lua_pop(hlua->T, 1);
10290 return 1;
10291
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010292 case HLUA_E_ETMOUT:
10293 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
10294 fcn->name);
10295 return 1;
10296
10297 case HLUA_E_NOMEM:
10298 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
10299 fcn->name);
10300 return 1;
10301
10302 case HLUA_E_YIELD: /* unexpected */
10303 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
10304 fcn->name);
10305 return 1;
10306
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010307 case HLUA_E_ERR:
10308 /* Display log. */
10309 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
10310 fcn->name);
10311 return 1;
10312
10313 default:
10314 return 1;
10315 }
10316
10317 return 1;
10318}
10319
10320static void hlua_cli_io_release_fct(struct appctx *appctx)
10321{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010322 struct hlua_cli_ctx *ctx = appctx->svcctx;
10323
10324 hlua_ctx_destroy(ctx->hlua);
10325 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010326}
10327
10328/* This function is an LUA binding used for registering
10329 * new keywords in the cli. It expects a list of keywords
10330 * which are the "path". It is limited to 5 keywords. A
10331 * description of the command, a function to be executed
10332 * for the parsing and a function for io handlers.
10333 */
10334__LJMP static int hlua_register_cli(lua_State *L)
10335{
10336 struct cli_kw_list *cli_kws;
10337 const char *message;
10338 int ref_io;
10339 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010340 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010341 int index;
10342 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010343 struct buffer *trash;
10344 const char *kw[5];
10345 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010346 const char *errmsg;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010347
10348 MAY_LJMP(check_args(L, 3, "register_cli"));
10349
10350 /* First argument : an array of maximum 5 keywords. */
10351 if (!lua_istable(L, 1))
10352 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
10353
10354 /* Second argument : string with contextual message. */
10355 message = MAY_LJMP(luaL_checkstring(L, 2));
10356
10357 /* Third and fourth argument : lua function. */
10358 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
10359
Thierry Fournierf67442e2020-11-28 20:41:07 +010010360 /* Check for CLI service already registered */
10361 trash = get_trash_chunk();
10362 index = 0;
10363 lua_pushnil(L);
10364 memset(kw, 0, sizeof(kw));
10365 while (lua_next(L, 1) != 0) {
10366 if (index >= CLI_PREFIX_KW_NB)
10367 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
10368 if (lua_type(L, -1) != LUA_TSTRING)
10369 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
10370 kw[index] = lua_tostring(L, -1);
10371 if (index == 0)
10372 chunk_printf(trash, "%s", kw[index]);
10373 else
10374 chunk_appendf(trash, " %s", kw[index]);
10375 index++;
10376 lua_pop(L, 1);
10377 }
10378 cli_kw = cli_find_kw_exact((char **)kw);
10379 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010380 fcn = cli_kw->private;
10381 if (fcn->function_ref[hlua_state_id] != -1) {
10382 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
10383 "This will become a hard error in version 2.5.\n", trash->area);
10384 }
10385 fcn->function_ref[hlua_state_id] = ref_io;
10386 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010387 }
10388
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010389 /* Allocate and fill the sample fetch keyword struct. */
10390 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010391 if (!cli_kws) {
10392 errmsg = "Lua out of memory error.";
10393 goto error;
10394 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010395 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010396 if (!fcn) {
10397 errmsg = "Lua out of memory error.";
10398 goto error;
10399 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010400
10401 /* Fill path. */
10402 index = 0;
10403 lua_pushnil(L);
10404 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010405 if (index >= 5) {
10406 errmsg = "1st argument must be a table with a maximum of 5 entries";
10407 goto error;
10408 }
10409 if (lua_type(L, -1) != LUA_TSTRING) {
10410 errmsg = "1st argument must be a table filled with strings";
10411 goto error;
10412 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010413 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010414 if (!cli_kws->kw[0].str_kw[index]) {
10415 errmsg = "Lua out of memory error.";
10416 goto error;
10417 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010418 index++;
10419 lua_pop(L, 1);
10420 }
10421
10422 /* Copy help message. */
10423 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010424 if (!cli_kws->kw[0].usage) {
10425 errmsg = "Lua out of memory error.";
10426 goto error;
10427 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010428
10429 /* Fill fcn io handler. */
10430 len = strlen("<lua.cli>") + 1;
10431 for (i = 0; i < index; i++)
10432 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
10433 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010434 if (!fcn->name) {
10435 errmsg = "Lua out of memory error.";
10436 goto error;
10437 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010438 strncat((char *)fcn->name, "<lua.cli", len);
10439 for (i = 0; i < index; i++) {
10440 strncat((char *)fcn->name, ".", len);
10441 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
10442 }
10443 strncat((char *)fcn->name, ">", len);
Thierry Fournierc7492592020-11-28 23:57:24 +010010444 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010445
10446 /* Fill last entries. */
10447 cli_kws->kw[0].private = fcn;
10448 cli_kws->kw[0].parse = hlua_cli_parse_fct;
10449 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
10450 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
10451
10452 /* Register this new converter */
10453 cli_register_kw(cli_kws);
10454
10455 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010456
10457 error:
10458 release_hlua_function(fcn);
10459 if (cli_kws) {
10460 for (i = 0; i < index; i++)
10461 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
10462 ha_free((char **)&(cli_kws->kw[0].usage));
10463 }
10464 ha_free(&cli_kws);
10465 WILL_LJMP(luaL_error(L, errmsg));
10466 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010467}
10468
Christopher Faulet69c581a2021-05-31 08:54:04 +020010469static int hlua_filter_init_per_thread(struct proxy *px, struct flt_conf *fconf)
10470{
10471 struct hlua_flt_config *conf = fconf->conf;
10472 lua_State *L;
10473 int error, pos, state_id, flt_ref;
10474
10475 state_id = reg_flt_to_stack_id(conf->reg);
10476 L = hlua_states[state_id];
10477 pos = lua_gettop(L);
10478
10479 /* The filter parsing function */
10480 lua_rawgeti(L, LUA_REGISTRYINDEX, conf->reg->fun_ref[state_id]);
10481
10482 /* Push the filter class on the stack and resolve all callbacks */
10483 lua_rawgeti(L, LUA_REGISTRYINDEX, conf->reg->flt_ref[state_id]);
10484
10485 /* Duplicate the filter class so each filter will have its own copy */
10486 lua_newtable(L);
10487 lua_pushnil(L);
10488
10489 while (lua_next(L, pos+2)) {
10490 lua_pushvalue(L, -2);
10491 lua_insert(L, -2);
10492 lua_settable(L, -4);
10493 }
10494 flt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
10495
10496 /* Remove the original lua filter class from the stack */
10497 lua_pop(L, 1);
10498
10499 /* Push the copy on the stack */
10500 lua_rawgeti(L, LUA_REGISTRYINDEX, flt_ref);
10501
10502 /* extra args are pushed in a table */
10503 lua_newtable(L);
10504 for (pos = 0; conf->args[pos]; pos++) {
10505 /* Check stack available size. */
10506 if (!lua_checkstack(L, 1)) {
10507 ha_alert("Lua filter '%s' : Lua error : full stack.", conf->reg->name);
10508 goto error;
10509 }
10510 lua_pushstring(L, conf->args[pos]);
10511 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
10512 }
10513
10514 error = lua_pcall(L, 2, LUA_MULTRET, 0);
10515 switch (error) {
10516 case LUA_OK:
10517 /* replace the filter ref */
10518 conf->ref[state_id] = flt_ref;
10519 break;
10520 case LUA_ERRRUN:
10521 ha_alert("Lua filter '%s' : runtime error : %s", conf->reg->name, lua_tostring(L, -1));
10522 goto error;
10523 case LUA_ERRMEM:
10524 ha_alert("Lua filter '%s' : out of memory error", conf->reg->name);
10525 goto error;
10526 case LUA_ERRERR:
10527 ha_alert("Lua filter '%s' : message handler error : %s", conf->reg->name, lua_tostring(L, -1));
10528 goto error;
10529#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
10530 case LUA_ERRGCMM:
10531 ha_alert("Lua filter '%s' : garbage collector error : %s", conf->reg->name, lua_tostring(L, -1));
10532 goto error;
10533#endif
10534 default:
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050010535 ha_alert("Lua filter '%s' : unknown error : %s", conf->reg->name, lua_tostring(L, -1));
Christopher Faulet69c581a2021-05-31 08:54:04 +020010536 goto error;
10537 }
10538
10539 lua_settop(L, 0);
10540 return 0;
10541
10542 error:
10543 lua_settop(L, 0);
10544 return -1;
10545}
10546
10547static void hlua_filter_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
10548{
10549 struct hlua_flt_config *conf = fconf->conf;
10550 lua_State *L;
10551 int state_id;
10552
10553 if (!conf)
10554 return;
10555
10556 state_id = reg_flt_to_stack_id(conf->reg);
10557 L = hlua_states[state_id];
10558 luaL_unref(L, LUA_REGISTRYINDEX, conf->ref[state_id]);
10559}
10560
10561static int hlua_filter_init(struct proxy *px, struct flt_conf *fconf)
10562{
10563 struct hlua_flt_config *conf = fconf->conf;
10564 int state_id = reg_flt_to_stack_id(conf->reg);
10565
10566 /* Rely on per-thread init for global scripts */
10567 if (!state_id)
10568 return hlua_filter_init_per_thread(px, fconf);
10569 return 0;
10570}
10571
10572static void hlua_filter_deinit(struct proxy *px, struct flt_conf *fconf)
10573{
10574
10575 if (fconf->conf) {
10576 struct hlua_flt_config *conf = fconf->conf;
10577 int state_id = reg_flt_to_stack_id(conf->reg);
10578 int pos;
10579
10580 /* Rely on per-thread deinit for global scripts */
10581 if (!state_id)
10582 hlua_filter_deinit_per_thread(px, fconf);
10583
10584 for (pos = 0; conf->args[pos]; pos++)
10585 free(conf->args[pos]);
10586 free(conf->args);
10587 }
10588 ha_free(&fconf->conf);
10589 ha_free((char **)&fconf->id);
10590 ha_free(&fconf->ops);
10591}
10592
10593static int hlua_filter_new(struct stream *s, struct filter *filter)
10594{
10595 struct hlua_flt_config *conf = FLT_CONF(filter);
10596 struct hlua_flt_ctx *flt_ctx = NULL;
10597 int ret = 1;
10598
10599 /* In the execution wrappers linked with a stream, the
10600 * Lua context can be not initialized. This behavior
10601 * permits to save performances because a systematic
10602 * Lua initialization cause 5% performances loss.
10603 */
10604 if (!s->hlua) {
10605 struct hlua *hlua;
10606
10607 hlua = pool_alloc(pool_head_hlua);
10608 if (!hlua) {
10609 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
10610 conf->reg->name);
10611 ret = 0;
10612 goto end;
10613 }
10614 HLUA_INIT(hlua);
10615 s->hlua = hlua;
10616 if (!hlua_ctx_init(s->hlua, reg_flt_to_stack_id(conf->reg), s->task, 0)) {
10617 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
10618 conf->reg->name);
10619 ret = 0;
10620 goto end;
10621 }
10622 }
10623
10624 flt_ctx = pool_zalloc(pool_head_hlua_flt_ctx);
10625 if (!flt_ctx) {
10626 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10627 conf->reg->name);
10628 ret = 0;
10629 goto end;
10630 }
10631 flt_ctx->hlua[0] = pool_alloc(pool_head_hlua);
10632 flt_ctx->hlua[1] = pool_alloc(pool_head_hlua);
10633 if (!flt_ctx->hlua[0] || !flt_ctx->hlua[1]) {
10634 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10635 conf->reg->name);
10636 ret = 0;
10637 goto end;
10638 }
10639 HLUA_INIT(flt_ctx->hlua[0]);
10640 HLUA_INIT(flt_ctx->hlua[1]);
10641 if (!hlua_ctx_init(flt_ctx->hlua[0], reg_flt_to_stack_id(conf->reg), s->task, 0) ||
10642 !hlua_ctx_init(flt_ctx->hlua[1], reg_flt_to_stack_id(conf->reg), s->task, 0)) {
10643 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10644 conf->reg->name);
10645 ret = 0;
10646 goto end;
10647 }
10648
10649 if (!HLUA_IS_RUNNING(s->hlua)) {
10650 /* The following Lua calls can fail. */
10651 if (!SET_SAFE_LJMP(s->hlua)) {
10652 const char *error;
10653
10654 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
10655 error = lua_tostring(s->hlua->T, -1);
10656 else
10657 error = "critical error";
10658 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
10659 ret = 0;
10660 goto end;
10661 }
10662
10663 /* Check stack size. */
10664 if (!lua_checkstack(s->hlua->T, 1)) {
10665 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
Tim Duesterhus22817382021-09-11 23:17:25 +020010666 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010667 ret = 0;
10668 goto end;
10669 }
10670
10671 lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, conf->ref[s->hlua->state_id]);
10672 if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) {
10673 SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
10674 conf->reg->name);
10675 RESET_SAFE_LJMP(s->hlua);
10676 ret = 0;
10677 goto end;
10678 }
10679 lua_insert(s->hlua->T, -2);
10680
10681 /* Push the copy on the stack */
10682 s->hlua->nargs = 1;
10683
10684 /* We must initialize the execution timeouts. */
10685 s->hlua->max_time = hlua_timeout_session;
10686
10687 /* At this point the execution is safe. */
10688 RESET_SAFE_LJMP(s->hlua);
10689 }
10690
10691 switch (hlua_ctx_resume(s->hlua, 0)) {
10692 case HLUA_E_OK:
10693 /* Nothing returned or not a table, ignore the filter for current stream */
10694 if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) {
10695 ret = 0;
10696 goto end;
10697 }
10698
10699 /* Attached the filter pointer to the ctx */
10700 lua_pushstring(s->hlua->T, "__filter");
10701 lua_pushlightuserdata(s->hlua->T, filter);
10702 lua_settable(s->hlua->T, -3);
10703
10704 /* Save a ref on the filter ctx */
10705 lua_pushvalue(s->hlua->T, 1);
10706 flt_ctx->ref = luaL_ref(s->hlua->T, LUA_REGISTRYINDEX);
10707 filter->ctx = flt_ctx;
10708 break;
10709 case HLUA_E_ERRMSG:
10710 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(s->hlua->T, -1));
10711 ret = -1;
10712 goto end;
10713 case HLUA_E_ETMOUT:
10714 SEND_ERR(s->be, "Lua filter '%s' : 'new' execution timeout.\n", conf->reg->name);
10715 ret = 0;
10716 goto end;
10717 case HLUA_E_NOMEM:
10718 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
10719 ret = 0;
10720 goto end;
10721 case HLUA_E_AGAIN:
10722 case HLUA_E_YIELD:
10723 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
10724 " are not allowed from 'new' function.\n", conf->reg->name);
10725 ret = 0;
10726 goto end;
10727 case HLUA_E_ERR:
10728 SEND_ERR(s->be, "Lua filter '%s': 'new' returns an unknown error.\n", conf->reg->name);
10729 ret = 0;
10730 goto end;
10731 default:
10732 ret = 0;
10733 goto end;
10734 }
10735
10736 end:
10737 if (s->hlua)
10738 lua_settop(s->hlua->T, 0);
10739 if (ret <= 0) {
10740 if (flt_ctx) {
10741 hlua_ctx_destroy(flt_ctx->hlua[0]);
10742 hlua_ctx_destroy(flt_ctx->hlua[1]);
10743 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
10744 }
10745 }
10746 return ret;
10747}
10748
10749static void hlua_filter_delete(struct stream *s, struct filter *filter)
10750{
10751 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10752
10753 luaL_unref(s->hlua->T, LUA_REGISTRYINDEX, flt_ctx->ref);
10754 hlua_ctx_destroy(flt_ctx->hlua[0]);
10755 hlua_ctx_destroy(flt_ctx->hlua[1]);
10756 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
10757 filter->ctx = NULL;
10758}
10759
Christopher Faulet9f55a502020-02-25 15:21:02 +010010760static int hlua_filter_from_payload(struct filter *filter)
10761{
10762 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10763
10764 return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD));
10765}
10766
Christopher Fauletc404f112020-02-26 15:03:09 +010010767static int hlua_filter_callback(struct stream *s, struct filter *filter, const char *fun,
10768 int dir, unsigned int flags)
10769{
10770 struct hlua *flt_hlua;
10771 struct hlua_flt_config *conf = FLT_CONF(filter);
10772 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10773 unsigned int hflags = HLUA_TXN_FLT_CTX;
10774 int ret = 1;
10775
10776 flt_hlua = flt_ctx->hlua[(dir == SMP_OPT_DIR_REQ ? 0 : 1)];
10777 if (!flt_hlua)
10778 goto end;
10779
10780 if (!HLUA_IS_RUNNING(flt_hlua)) {
10781 int extra_idx = lua_gettop(flt_hlua->T);
10782
10783 /* The following Lua calls can fail. */
10784 if (!SET_SAFE_LJMP(flt_hlua)) {
10785 const char *error;
10786
10787 if (lua_type(flt_hlua->T, -1) == LUA_TSTRING)
10788 error = lua_tostring(flt_hlua->T, -1);
10789 else
10790 error = "critical error";
10791 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
10792 goto end;
10793 }
10794
10795 /* Check stack size. */
10796 if (!lua_checkstack(flt_hlua->T, 3)) {
10797 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10798 RESET_SAFE_LJMP(flt_hlua);
10799 goto end;
10800 }
10801
10802 lua_rawgeti(flt_hlua->T, LUA_REGISTRYINDEX, flt_ctx->ref);
10803 if (lua_getfield(flt_hlua->T, -1, fun) != LUA_TFUNCTION) {
10804 RESET_SAFE_LJMP(flt_hlua);
10805 goto end;
10806 }
10807 lua_insert(flt_hlua->T, -2);
10808
10809 if (!hlua_txn_new(flt_hlua->T, s, s->be, dir, hflags)) {
10810 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10811 RESET_SAFE_LJMP(flt_hlua);
10812 goto end;
10813 }
10814 flt_hlua->nargs = 2;
10815
10816 if (flags & HLUA_FLT_CB_ARG_CHN) {
10817 if (dir == SMP_OPT_DIR_REQ)
10818 lua_getfield(flt_hlua->T, -1, "req");
10819 else
10820 lua_getfield(flt_hlua->T, -1, "res");
10821 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
10822 lua_pushstring(flt_hlua->T, "__filter");
10823 lua_pushlightuserdata(flt_hlua->T, filter);
10824 lua_settable(flt_hlua->T, -3);
10825 }
10826 flt_hlua->nargs++;
10827 }
10828 else if (flags & HLUA_FLT_CB_ARG_HTTP_MSG) {
Christopher Fauleteae8afa2020-02-26 17:15:48 +010010829 if (dir == SMP_OPT_DIR_REQ)
10830 lua_getfield(flt_hlua->T, -1, "http_req");
10831 else
10832 lua_getfield(flt_hlua->T, -1, "http_res");
10833 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
10834 lua_pushstring(flt_hlua->T, "__filter");
10835 lua_pushlightuserdata(flt_hlua->T, filter);
10836 lua_settable(flt_hlua->T, -3);
10837 }
10838 flt_hlua->nargs++;
Christopher Fauletc404f112020-02-26 15:03:09 +010010839 }
10840
10841 /* Check stack size. */
10842 if (!lua_checkstack(flt_hlua->T, 1)) {
10843 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10844 RESET_SAFE_LJMP(flt_hlua);
10845 goto end;
10846 }
10847
10848 while (extra_idx--) {
10849 lua_pushvalue(flt_hlua->T, 1);
10850 lua_remove(flt_hlua->T, 1);
10851 flt_hlua->nargs++;
10852 }
10853
10854 /* We must initialize the execution timeouts. */
10855 flt_hlua->max_time = hlua_timeout_session;
10856
10857 /* At this point the execution is safe. */
10858 RESET_SAFE_LJMP(flt_hlua);
10859 }
10860
10861 switch (hlua_ctx_resume(flt_hlua, !(flags & HLUA_FLT_CB_FINAL))) {
10862 case HLUA_E_OK:
10863 /* Catch the return value if it required */
10864 if ((flags & HLUA_FLT_CB_RETVAL) && lua_gettop(flt_hlua->T) > 0) {
10865 ret = lua_tointeger(flt_hlua->T, -1);
10866 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
10867 }
10868
10869 /* Set timeout in the required channel. */
10870 if (flt_hlua->wake_time != TICK_ETERNITY) {
10871 if (dir == SMP_OPT_DIR_REQ)
10872 s->req.analyse_exp = flt_hlua->wake_time;
10873 else
10874 s->res.analyse_exp = flt_hlua->wake_time;
10875 }
10876 break;
10877 case HLUA_E_AGAIN:
10878 /* Set timeout in the required channel. */
10879 if (flt_hlua->wake_time != TICK_ETERNITY) {
10880 if (dir == SMP_OPT_DIR_REQ)
10881 s->req.analyse_exp = flt_hlua->wake_time;
10882 else
10883 s->res.analyse_exp = flt_hlua->wake_time;
10884 }
10885 /* Some actions can be wake up when a "write" event
10886 * is detected on a response channel. This is useful
10887 * only for actions targeted on the requests.
10888 */
10889 if (HLUA_IS_WAKERESWR(flt_hlua))
10890 s->res.flags |= CF_WAKE_WRITE;
10891 if (HLUA_IS_WAKEREQWR(flt_hlua))
10892 s->req.flags |= CF_WAKE_WRITE;
10893 ret = 0;
10894 goto end;
10895 case HLUA_E_ERRMSG:
10896 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(flt_hlua->T, -1));
10897 ret = -1;
10898 goto end;
10899 case HLUA_E_ETMOUT:
10900 SEND_ERR(s->be, "Lua filter '%s' : '%s' callback execution timeout.\n", conf->reg->name, fun);
10901 goto end;
10902 case HLUA_E_NOMEM:
10903 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
10904 goto end;
10905 case HLUA_E_YIELD:
10906 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
10907 " are not allowed from '%s' callback.\n", conf->reg->name, fun);
10908 goto end;
10909 case HLUA_E_ERR:
10910 SEND_ERR(s->be, "Lua filter '%s': '%s' returns an unknown error.\n", conf->reg->name, fun);
10911 goto end;
10912 default:
10913 goto end;
10914 }
10915
10916
10917 end:
10918 return ret;
10919}
10920
10921static int hlua_filter_start_analyze(struct stream *s, struct filter *filter, struct channel *chn)
10922{
10923 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10924
10925 flt_ctx->flags = 0;
10926 return hlua_filter_callback(s, filter, "start_analyze",
10927 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10928 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
10929}
10930
10931static int hlua_filter_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
10932{
10933 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10934
10935 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
10936 return hlua_filter_callback(s, filter, "end_analyze",
10937 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10938 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
10939}
10940
Christopher Fauleteae8afa2020-02-26 17:15:48 +010010941static int hlua_filter_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
10942{
10943 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10944
10945 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
10946 return hlua_filter_callback(s, filter, "http_headers",
10947 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10948 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
10949}
10950
10951static int hlua_filter_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
10952 unsigned int offset, unsigned int len)
10953{
10954 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10955 struct hlua *flt_hlua;
10956 int dir = (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
10957 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
10958 int ret;
10959
10960 flt_hlua = flt_ctx->hlua[idx];
10961 flt_ctx->cur_off[idx] = offset;
10962 flt_ctx->cur_len[idx] = len;
10963 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
10964 ret = hlua_filter_callback(s, filter, "http_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_HTTP_MSG));
10965 if (ret != -1) {
10966 ret = flt_ctx->cur_len[idx];
10967 if (lua_gettop(flt_hlua->T) > 0) {
10968 ret = lua_tointeger(flt_hlua->T, -1);
10969 if (ret > flt_ctx->cur_len[idx])
10970 ret = flt_ctx->cur_len[idx];
10971 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
10972 }
10973 }
10974 return ret;
10975}
10976
10977static int hlua_filter_http_end(struct stream *s, struct filter *filter, struct http_msg *msg)
10978{
10979 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10980
10981 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
10982 return hlua_filter_callback(s, filter, "http_end",
10983 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
10984 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
10985}
10986
Christopher Fauletc404f112020-02-26 15:03:09 +010010987static int hlua_filter_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
10988 unsigned int offset, unsigned int len)
10989{
10990 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10991 struct hlua *flt_hlua;
10992 int dir = (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
10993 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
10994 int ret;
10995
10996 flt_hlua = flt_ctx->hlua[idx];
10997 flt_ctx->cur_off[idx] = offset;
10998 flt_ctx->cur_len[idx] = len;
10999 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
11000 ret = hlua_filter_callback(s, filter, "tcp_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_CHN));
11001 if (ret != -1) {
11002 ret = flt_ctx->cur_len[idx];
11003 if (lua_gettop(flt_hlua->T) > 0) {
11004 ret = lua_tointeger(flt_hlua->T, -1);
11005 if (ret > flt_ctx->cur_len[idx])
11006 ret = flt_ctx->cur_len[idx];
11007 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11008 }
11009 }
11010 return ret;
11011}
11012
Christopher Faulet69c581a2021-05-31 08:54:04 +020011013static int hlua_filter_parse_fct(char **args, int *cur_arg, struct proxy *px,
11014 struct flt_conf *fconf, char **err, void *private)
11015{
11016 struct hlua_reg_filter *reg_flt = private;
11017 lua_State *L;
11018 struct hlua_flt_config *conf = NULL;
11019 const char *flt_id = NULL;
11020 int state_id, pos, flt_flags = 0;
11021 struct flt_ops *hlua_flt_ops = NULL;
11022
11023 state_id = reg_flt_to_stack_id(reg_flt);
11024 L = hlua_states[state_id];
11025
11026 /* Initialize the filter ops with default callbacks */
11027 hlua_flt_ops = calloc(1, sizeof(*hlua_flt_ops));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011028 if (!hlua_flt_ops)
11029 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011030 hlua_flt_ops->init = hlua_filter_init;
11031 hlua_flt_ops->deinit = hlua_filter_deinit;
11032 if (state_id) {
11033 /* Set per-thread callback if script is loaded per-thread */
11034 hlua_flt_ops->init_per_thread = hlua_filter_init_per_thread;
11035 hlua_flt_ops->deinit_per_thread = hlua_filter_deinit_per_thread;
11036 }
11037 hlua_flt_ops->attach = hlua_filter_new;
11038 hlua_flt_ops->detach = hlua_filter_delete;
11039
11040 /* Push the filter class on the stack and resolve all callbacks */
11041 lua_rawgeti(L, LUA_REGISTRYINDEX, reg_flt->flt_ref[state_id]);
11042
Christopher Fauletc404f112020-02-26 15:03:09 +010011043 if (lua_getfield(L, -1, "start_analyze") == LUA_TFUNCTION)
11044 hlua_flt_ops->channel_start_analyze = hlua_filter_start_analyze;
11045 lua_pop(L, 1);
11046 if (lua_getfield(L, -1, "end_analyze") == LUA_TFUNCTION)
11047 hlua_flt_ops->channel_end_analyze = hlua_filter_end_analyze;
11048 lua_pop(L, 1);
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011049 if (lua_getfield(L, -1, "http_headers") == LUA_TFUNCTION)
11050 hlua_flt_ops->http_headers = hlua_filter_http_headers;
11051 lua_pop(L, 1);
11052 if (lua_getfield(L, -1, "http_payload") == LUA_TFUNCTION)
11053 hlua_flt_ops->http_payload = hlua_filter_http_payload;
11054 lua_pop(L, 1);
11055 if (lua_getfield(L, -1, "http_end") == LUA_TFUNCTION)
11056 hlua_flt_ops->http_end = hlua_filter_http_end;
11057 lua_pop(L, 1);
Christopher Fauletc404f112020-02-26 15:03:09 +010011058 if (lua_getfield(L, -1, "tcp_payload") == LUA_TFUNCTION)
11059 hlua_flt_ops->tcp_payload = hlua_filter_tcp_payload;
11060 lua_pop(L, 1);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011061
11062 /* Get id and flags of the filter class */
11063 if (lua_getfield(L, -1, "id") == LUA_TSTRING)
11064 flt_id = lua_tostring(L, -1);
11065 lua_pop(L, 1);
11066 if (lua_getfield(L, -1, "flags") == LUA_TNUMBER)
11067 flt_flags = lua_tointeger(L, -1);
11068 lua_pop(L, 1);
11069
11070 /* Create the filter config */
11071 conf = calloc(1, sizeof(*conf));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011072 if (!conf)
Christopher Faulet69c581a2021-05-31 08:54:04 +020011073 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011074 conf->reg = reg_flt;
11075
11076 /* duplicate args */
11077 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++);
11078 conf->args = calloc(pos + 1, sizeof(*conf->args));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011079 if (!conf->args)
11080 goto error;
11081 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020011082 conf->args[pos] = strdup(args[*cur_arg + 1 + pos]);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011083 if (!conf->args[pos])
11084 goto error;
11085 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011086 conf->args[pos] = NULL;
11087 *cur_arg += pos + 1;
11088
Christopher Fauletc86bb872021-08-13 08:33:57 +020011089 if (flt_id) {
11090 fconf->id = strdup(flt_id);
11091 if (!fconf->id)
11092 goto error;
11093 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011094 fconf->flags = flt_flags;
11095 fconf->conf = conf;
11096 fconf->ops = hlua_flt_ops;
11097
11098 lua_settop(L, 0);
11099 return 0;
11100
11101 error:
Christopher Fauletc86bb872021-08-13 08:33:57 +020011102 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011103 free(hlua_flt_ops);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011104 if (conf && conf->args) {
11105 for (pos = 0; conf->args[pos]; pos++)
11106 free(conf->args[pos]);
11107 free(conf->args);
11108 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011109 free(conf);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011110 free((char *)fconf->id);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011111 lua_settop(L, 0);
11112 return -1;
11113}
11114
Christopher Fauletc404f112020-02-26 15:03:09 +010011115__LJMP static int hlua_register_data_filter(lua_State *L)
11116{
11117 struct filter *filter;
11118 struct channel *chn;
11119
11120 MAY_LJMP(check_args(L, 2, "register_data_filter"));
11121 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
11122 chn = MAY_LJMP(hlua_checkchannel(L, 2));
11123
11124 lua_getfield(L, 1, "__filter");
11125 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
11126 filter = lua_touserdata (L, -1);
11127 lua_pop(L, 1);
11128
11129 register_data_filter(chn_strm(chn), chn, filter);
11130 return 1;
11131}
11132
11133__LJMP static int hlua_unregister_data_filter(lua_State *L)
11134{
11135 struct filter *filter;
11136 struct channel *chn;
11137
11138 MAY_LJMP(check_args(L, 2, "unregister_data_filter"));
11139 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
11140 chn = MAY_LJMP(hlua_checkchannel(L, 2));
11141
11142 lua_getfield(L, 1, "__filter");
11143 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
11144 filter = lua_touserdata (L, -1);
11145 lua_pop(L, 1);
11146
11147 unregister_data_filter(chn_strm(chn), chn, filter);
11148 return 1;
11149}
11150
Christopher Faulet69c581a2021-05-31 08:54:04 +020011151/* This function is an LUA binding used for registering a filter. It expects a
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050011152 * filter name used in the haproxy configuration file and a LUA function to
Christopher Faulet69c581a2021-05-31 08:54:04 +020011153 * parse configuration arguments.
11154 */
11155__LJMP static int hlua_register_filter(lua_State *L)
11156{
11157 struct buffer *trash;
11158 struct flt_kw_list *fkl;
11159 struct flt_kw *fkw;
11160 const char *name;
11161 struct hlua_reg_filter *reg_flt= NULL;
11162 int flt_ref, fun_ref;
11163 int len;
11164
11165 MAY_LJMP(check_args(L, 3, "register_filter"));
11166
11167 /* First argument : filter name. */
11168 name = MAY_LJMP(luaL_checkstring(L, 1));
11169
11170 /* Second argument : The filter class */
11171 flt_ref = MAY_LJMP(hlua_checktable(L, 2));
11172
11173 /* Third argument : lua function. */
11174 fun_ref = MAY_LJMP(hlua_checkfunction(L, 3));
11175
11176 trash = get_trash_chunk();
11177 chunk_printf(trash, "lua.%s", name);
11178 fkw = flt_find_kw(trash->area);
11179 if (fkw != NULL) {
11180 reg_flt = fkw->private;
11181 if (reg_flt->flt_ref[hlua_state_id] != -1 || reg_flt->fun_ref[hlua_state_id] != -1) {
11182 ha_warning("Trying to register filter 'lua.%s' more than once. "
11183 "This will become a hard error in version 2.5.\n", name);
11184 }
11185 reg_flt->flt_ref[hlua_state_id] = flt_ref;
11186 reg_flt->fun_ref[hlua_state_id] = fun_ref;
11187 return 0;
11188 }
11189
11190 fkl = calloc(1, sizeof(*fkl) + sizeof(struct flt_kw) * 2);
11191 if (!fkl)
11192 goto alloc_error;
11193 fkl->scope = "HLUA";
11194
11195 reg_flt = new_hlua_reg_filter(name);
11196 if (!reg_flt)
11197 goto alloc_error;
11198
11199 reg_flt->flt_ref[hlua_state_id] = flt_ref;
11200 reg_flt->fun_ref[hlua_state_id] = fun_ref;
11201
11202 /* The filter keyword */
11203 len = strlen("lua.") + strlen(name) + 1;
11204 fkl->kw[0].kw = calloc(1, len);
11205 if (!fkl->kw[0].kw)
11206 goto alloc_error;
11207
11208 snprintf((char *)fkl->kw[0].kw, len, "lua.%s", name);
11209
11210 fkl->kw[0].parse = hlua_filter_parse_fct;
11211 fkl->kw[0].private = reg_flt;
11212 memset(&fkl->kw[1], 0, sizeof(*fkl->kw));
11213
11214 /* Register this new filter */
11215 flt_register_keywords(fkl);
11216
11217 return 0;
11218
11219 alloc_error:
11220 release_hlua_reg_filter(reg_flt);
11221 ha_free(&fkl);
11222 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11223 return 0; /* Never reached */
11224}
11225
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011226static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011227 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011228 char **err, unsigned int *timeout)
11229{
11230 const char *error;
11231
11232 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +020011233 if (error == PARSE_TIME_OVER) {
11234 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
11235 args[1], args[0]);
11236 return -1;
11237 }
11238 else if (error == PARSE_TIME_UNDER) {
11239 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
11240 args[1], args[0]);
11241 return -1;
11242 }
11243 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011244 memprintf(err, "%s: invalid timeout", args[0]);
11245 return -1;
11246 }
11247 return 0;
11248}
11249
11250static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011251 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011252 char **err)
11253{
11254 return hlua_read_timeout(args, section_type, curpx, defpx,
11255 file, line, err, &hlua_timeout_session);
11256}
11257
11258static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011259 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011260 char **err)
11261{
11262 return hlua_read_timeout(args, section_type, curpx, defpx,
11263 file, line, err, &hlua_timeout_task);
11264}
11265
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011266static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011267 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011268 char **err)
11269{
11270 return hlua_read_timeout(args, section_type, curpx, defpx,
11271 file, line, err, &hlua_timeout_applet);
11272}
11273
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011274static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011275 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011276 char **err)
11277{
11278 char *error;
11279
11280 hlua_nb_instruction = strtoll(args[1], &error, 10);
11281 if (*error != '\0') {
11282 memprintf(err, "%s: invalid number", args[0]);
11283 return -1;
11284 }
11285 return 0;
11286}
11287
Willy Tarreau32f61e22015-03-18 17:54:59 +010011288static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011289 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +010011290 char **err)
11291{
11292 char *error;
11293
11294 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011295 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).", args[0]);
Willy Tarreau32f61e22015-03-18 17:54:59 +010011296 return -1;
11297 }
11298 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
11299 if (*error != '\0') {
11300 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
11301 return -1;
11302 }
11303 return 0;
11304}
11305
11306
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011307/* This function is called by the main configuration key "lua-load". It loads and
11308 * execute an lua file during the parsing of the HAProxy configuration file. It is
11309 * the main lua entry point.
11310 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080011311 * This function runs with the HAProxy keywords API. It returns -1 if an error
11312 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011313 *
11314 * In some error case, LUA set an error message in top of the stack. This function
11315 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020011316 *
11317 * This function can fail with an abort() due to an Lua critical error.
11318 * We are in the configuration parsing process of HAProxy, this abort() is
11319 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011320 */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011321static int hlua_load_state(char **args, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011322{
11323 int error;
Thierry Fournierae6b5682022-09-19 09:04:16 +020011324 int nargs;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011325
11326 /* Just load and compile the file. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011327 error = luaL_loadfile(L, args[0]);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011328 if (error) {
Thierry Fournierae6b5682022-09-19 09:04:16 +020011329 memprintf(err, "error in Lua file '%s': %s", args[0], lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011330 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011331 return -1;
11332 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011333
11334 /* Push args in the Lua stack, except the first one which is the filename */
11335 for (nargs = 1; *(args[nargs]) != 0; nargs++) {
Aurelien DARRAGON4d7aefe2022-09-23 10:22:14 +020011336 /* Check stack size. */
11337 if (!lua_checkstack(L, 1)) {
11338 memprintf(err, "Lua runtime error while loading arguments: stack is full.");
11339 return -1;
11340 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011341 lua_pushstring(L, args[nargs]);
11342 }
11343 nargs--;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011344
11345 /* If no syntax error where detected, execute the code. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011346 error = lua_pcall(L, nargs, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011347 switch (error) {
11348 case LUA_OK:
11349 break;
11350 case LUA_ERRRUN:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011351 memprintf(err, "Lua runtime error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011352 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011353 return -1;
11354 case LUA_ERRMEM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011355 memprintf(err, "Lua out of memory error");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011356 return -1;
11357 case LUA_ERRERR:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011358 memprintf(err, "Lua message handler 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#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011362 case LUA_ERRGCMM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011363 memprintf(err, "Lua garbage collector 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;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020011366#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011367 default:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011368 memprintf(err, "Lua unknown error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011369 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011370 return -1;
11371 }
11372
11373 return 0;
11374}
11375
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011376static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011377 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011378 char **err)
11379{
11380 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011381 memprintf(err, "'%s' expects a file name as parameter.", args[0]);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011382 return -1;
11383 }
11384
Thierry Fournier59f11be2020-11-29 00:37:41 +010011385 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +010011386 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011387 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020011388 return hlua_load_state(&args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011389}
11390
Thierry Fournier59f11be2020-11-29 00:37:41 +010011391static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011392 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +010011393 char **err)
11394{
11395 int len;
Thierry Fournierae6b5682022-09-19 09:04:16 +020011396 int i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011397
11398 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011399 memprintf(err, "'%s' expects a file as parameter.", args[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011400 return -1;
11401 }
11402
11403 if (per_thread_load == NULL) {
11404 /* allocate the first entry large enough to store the final NULL */
11405 per_thread_load = calloc(1, sizeof(*per_thread_load));
11406 if (per_thread_load == NULL) {
11407 memprintf(err, "out of memory error");
11408 return -1;
11409 }
11410 }
11411
11412 /* count used entries */
11413 for (len = 0; per_thread_load[len] != NULL; len++)
11414 ;
11415
11416 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
11417 if (per_thread_load == NULL) {
11418 memprintf(err, "out of memory error");
11419 return -1;
11420 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010011421 per_thread_load[len + 1] = NULL;
11422
Thierry Fournierae6b5682022-09-19 09:04:16 +020011423 /* count args excepting the first, allocate array and copy args */
11424 for (i = 0; *(args[i + 1]) != 0; i++);
Aurelien DARRAGONb12d1692022-09-23 08:48:34 +020011425 per_thread_load[len] = calloc(i + 1, sizeof(*per_thread_load[len]));
Thierry Fournier59f11be2020-11-29 00:37:41 +010011426 if (per_thread_load[len] == NULL) {
11427 memprintf(err, "out of memory error");
11428 return -1;
11429 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011430 for (i = 1; *(args[i]) != 0; i++) {
11431 per_thread_load[len][i - 1] = strdup(args[i]);
11432 if (per_thread_load[len][i - 1] == NULL) {
11433 memprintf(err, "out of memory error");
11434 return -1;
11435 }
11436 }
11437 per_thread_load[len][i - 1] = strdup("");
11438 if (per_thread_load[len][i - 1] == NULL) {
11439 memprintf(err, "out of memory error");
11440 return -1;
11441 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010011442
11443 /* loading for thread 1 only */
11444 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011445 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020011446 return hlua_load_state(per_thread_load[len], hlua_states[1], err);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011447}
11448
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011449/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
11450 * in the given <ctx>.
11451 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +010011452static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011453{
Thierry Fournier3fb9e512020-11-28 10:13:12 +010011454 lua_getglobal(L, "package"); /* push package variable */
11455 lua_pushstring(L, path); /* push given path */
11456 lua_pushstring(L, ";"); /* push semicolon */
11457 lua_getfield(L, -3, type); /* push old path */
11458 lua_concat(L, 3); /* concatenate to new path */
11459 lua_setfield(L, -2, type); /* store new path */
11460 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011461
11462 return 0;
11463}
11464
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011465static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011466 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011467 char **err)
11468{
11469 char *path;
11470 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011471 struct prepend_path *p = NULL;
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000011472 size_t i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011473
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011474 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011475 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011476 }
11477
11478 if (!(*args[1])) {
11479 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011480 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011481 }
11482 path = args[1];
11483
11484 if (*args[2]) {
11485 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
11486 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011487 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011488 }
11489 type = args[2];
11490 }
11491
Thierry Fournier59f11be2020-11-29 00:37:41 +010011492 p = calloc(1, sizeof(*p));
11493 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011494 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011495 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011496 }
11497 p->path = strdup(path);
11498 if (p->path == 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 }
11502 p->type = strdup(type);
11503 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011504 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011505 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011506 }
Willy Tarreau2b718102021-04-21 07:32:39 +020011507 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011508
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020011509 /* Handle the global state and the per-thread state for the first
11510 * thread. The remaining threads will be initialized based on
11511 * prepend_path_list.
11512 */
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000011513 for (i = 0; i < 2; i++) {
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020011514 lua_State *L = hlua_states[i];
11515 const char *error;
11516
11517 if (setjmp(safe_ljmp_env) != 0) {
11518 lua_atpanic(L, hlua_panic_safe);
11519 if (lua_type(L, -1) == LUA_TSTRING)
11520 error = lua_tostring(L, -1);
11521 else
11522 error = "critical error";
11523 fprintf(stderr, "lua-prepend-path: %s.\n", error);
11524 exit(1);
11525 } else {
11526 lua_atpanic(L, hlua_panic_ljmp);
11527 }
11528
11529 hlua_prepend_path(L, type, path);
11530
11531 lua_atpanic(L, hlua_panic_safe);
11532 }
11533
Thierry Fournier59f11be2020-11-29 00:37:41 +010011534 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011535
11536err2:
11537 free(p->type);
11538 free(p->path);
11539err:
11540 free(p);
11541 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011542}
11543
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011544/* configuration keywords declaration */
11545static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011546 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011547 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +010011548 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011549 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
11550 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +020011551 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011552 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +010011553 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011554 { 0, NULL, NULL },
11555}};
11556
Willy Tarreau0108d902018-11-25 19:14:37 +010011557INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
11558
William Lallemand52139182022-03-30 15:05:42 +020011559#ifdef USE_OPENSSL
Christopher Fauletafd8f102018-11-08 11:34:21 +010011560
William Lallemand30fcca12022-03-30 12:03:12 +020011561/*
11562 * This function replace a ckch_store by another one, and rebuild the ckch_inst and all its dependencies.
11563 * It does the sam as "cli_io_handler_commit_cert" but for lua, the major
11564 * difference is that the yield in lua and for the CLI is not handled the same
11565 * way.
11566 */
11567__LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext ctx)
11568{
11569 struct ckch_inst **lua_ckchi = lua_touserdata(L, -1);
11570 struct ckch_store **lua_ckchs = lua_touserdata(L, -2);
11571 struct ckch_inst *ckchi = *lua_ckchi;
11572 struct ckch_store *old_ckchs = lua_ckchs[0];
11573 struct ckch_store *new_ckchs = lua_ckchs[1];
11574 struct hlua *hlua;
11575 char *err = NULL;
11576 int y = 1;
11577
11578 hlua = hlua_gethlua(L);
11579
11580 /* get the first ckchi to copy */
11581 if (ckchi == NULL)
11582 ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
11583
11584 /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
11585 list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
11586 struct ckch_inst *new_inst;
11587
11588 /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
11589 if (y % 10 == 0) {
11590
11591 *lua_ckchi = ckchi;
11592
11593 task_wakeup(hlua->task, TASK_WOKEN_MSG);
11594 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
11595 }
11596
11597 if (ckch_inst_rebuild(new_ckchs, ckchi, &new_inst, &err))
11598 goto error;
11599
11600 /* link the new ckch_inst to the duplicate */
11601 LIST_APPEND(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
11602 y++;
11603 }
11604
11605 /* The generation is finished, we can insert everything */
11606 ckch_store_replace(old_ckchs, new_ckchs);
11607
11608 lua_pop(L, 2); /* pop the lua_ckchs and ckchi */
11609
11610 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11611
11612 return 0;
11613
11614error:
11615 ckch_store_free(new_ckchs);
11616 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11617 WILL_LJMP(luaL_error(L, "%s", err));
11618 free(err);
11619
11620 return 0;
11621}
11622
11623/*
11624 * Replace a ckch_store <filename> in the ckchs_tree with a ckch_store created
11625 * from the table in parameter.
11626 *
11627 * This is equivalent to "set ssl cert" + "commit ssl cert" over the CLI, which
11628 * means it does not need to have a transaction since everything is done in the
11629 * same function.
11630 *
11631 * CertCache.set{filename="", crt="", key="", sctl="", ocsp="", issuer=""}
11632 *
11633 */
11634__LJMP static int hlua_ckch_set(lua_State *L)
11635{
11636 struct hlua *hlua;
11637 struct ckch_inst **lua_ckchi;
11638 struct ckch_store **lua_ckchs;
11639 struct ckch_store *old_ckchs = NULL;
11640 struct ckch_store *new_ckchs = NULL;
11641 int errcode = 0;
11642 char *err = NULL;
11643 struct cert_exts *cert_ext = NULL;
11644 char *filename;
William Lallemand52ddd992022-11-22 11:51:53 +010011645 struct ckch_data *data;
William Lallemand30fcca12022-03-30 12:03:12 +020011646 int ret;
11647
11648 if (lua_type(L, -1) != LUA_TTABLE)
11649 WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
11650
11651 hlua = hlua_gethlua(L);
11652
11653 /* FIXME: this should not return an error but should come back later */
11654 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
11655 WILL_LJMP(luaL_error(L, "CertCache already under lock"));
11656
11657 ret = lua_getfield(L, -1, "filename");
11658 if (ret != LUA_TSTRING) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011659 memprintf(&err, "%sNo filename specified!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011660 errcode |= ERR_ALERT | ERR_FATAL;
11661 goto end;
11662 }
11663 filename = (char *)lua_tostring(L, -1);
11664
11665
11666 /* look for the filename in the tree */
11667 old_ckchs = ckchs_lookup(filename);
11668 if (!old_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011669 memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011670 errcode |= ERR_ALERT | ERR_FATAL;
11671 goto end;
11672 }
11673 /* TODO: handle extra_files_noext */
11674
11675 new_ckchs = ckchs_dup(old_ckchs);
11676 if (!new_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011677 memprintf(&err, "%sCannot allocate memory!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011678 errcode |= ERR_ALERT | ERR_FATAL;
11679 goto end;
11680 }
11681
William Lallemand52ddd992022-11-22 11:51:53 +010011682 data = new_ckchs->data;
William Lallemand30fcca12022-03-30 12:03:12 +020011683
11684 /* loop on the field in the table, which have the same name as the
11685 * possible extensions of files */
11686 lua_pushnil(L);
11687 while (lua_next(L, 1)) {
11688 int i;
11689 const char *field = lua_tostring(L, -2);
11690 char *payload = (char *)lua_tostring(L, -1);
11691
11692 if (!field || strcmp(field, "filename") == 0) {
11693 lua_pop(L, 1);
11694 continue;
11695 }
11696
11697 for (i = 0; field && cert_exts[i].ext != NULL; i++) {
11698 if (strcmp(field, cert_exts[i].ext) == 0) {
11699 cert_ext = &cert_exts[i];
11700 break;
11701 }
11702 }
11703
11704 /* this is the default type, the field is not supported */
11705 if (cert_ext == NULL) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011706 memprintf(&err, "%sUnsupported field '%s'", err ? err : "", field);
William Lallemand30fcca12022-03-30 12:03:12 +020011707 errcode |= ERR_ALERT | ERR_FATAL;
11708 goto end;
11709 }
11710
11711 /* appply the change on the duplicate */
William Lallemand52ddd992022-11-22 11:51:53 +010011712 if (cert_ext->load(filename, payload, data, &err) != 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011713 memprintf(&err, "%sCan't load the payload for '%s'", err ? err : "", cert_ext->ext);
William Lallemand30fcca12022-03-30 12:03:12 +020011714 errcode |= ERR_ALERT | ERR_FATAL;
11715 goto end;
11716 }
11717 lua_pop(L, 1);
11718 }
11719
11720 /* store the pointers on the lua stack */
11721 lua_ckchs = lua_newuserdata(L, sizeof(struct ckch_store *) * 2);
11722 lua_ckchs[0] = old_ckchs;
11723 lua_ckchs[1] = new_ckchs;
11724 lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
11725 *lua_ckchi = NULL;
11726
11727 task_wakeup(hlua->task, TASK_WOKEN_MSG);
11728 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
11729
11730end:
11731 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11732
11733 if (errcode & ERR_CODE) {
11734 ckch_store_free(new_ckchs);
11735 WILL_LJMP(luaL_error(L, "%s", err));
11736 }
11737 free(err);
11738
11739 return 0;
11740}
11741
William Lallemand52139182022-03-30 15:05:42 +020011742#else
11743
11744__LJMP static int hlua_ckch_set(lua_State *L)
11745{
11746 WILL_LJMP(luaL_error(L, "'CertCache.set' needs an HAProxy built with OpenSSL"));
11747
11748 return 0;
11749}
11750#endif /* ! USE_OPENSSL */
11751
11752
11753
Thierry FOURNIERbabae282015-09-17 11:36:37 +020011754/* This function can fail with an abort() due to an Lua critical error.
11755 * We are in the initialisation process of HAProxy, this abort() is
11756 * tolerated.
11757 */
Thierry Fournierb8cef172020-11-28 15:37:17 +010011758int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011759{
11760 struct hlua_init_function *init;
11761 const char *msg;
11762 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +010011763 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +010011764 const char *kind;
11765 const char *trace;
11766 int return_status = 1;
11767#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
11768 int nres;
11769#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011770
Willy Tarreaucdb53462020-12-02 12:12:00 +010011771 /* disable memory limit checks if limit is not set */
11772 if (!hlua_global_allocator.limit)
11773 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
11774
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050011775 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +010011776 if (setjmp(safe_ljmp_env) != 0) {
11777 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +010011778 if (lua_type(L, -1) == LUA_TSTRING)
11779 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011780 else
11781 error = "critical error";
11782 fprintf(stderr, "Lua post-init: %s.\n", error);
11783 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010011784 } else {
11785 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011786 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +020011787
Thierry Fournierb8cef172020-11-28 15:37:17 +010011788 hlua_fcn_post_init(L);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011789
Thierry Fournierc7492592020-11-28 23:57:24 +010011790 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010011791 lua_rawgeti(L, LUA_REGISTRYINDEX, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +010011792
11793#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +010011794 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +010011795#else
Thierry Fournierb8cef172020-11-28 15:37:17 +010011796 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +010011797#endif
11798 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011799 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +010011800
11801 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +010011802 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +010011803 break;
Thierry Fournier670db242020-11-28 10:49:59 +010011804
11805 case LUA_ERRERR:
11806 kind = "message handler error";
Willy Tarreau14de3952022-11-14 07:08:28 +010011807 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011808 case LUA_ERRRUN:
11809 if (!kind)
11810 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010011811 msg = lua_tostring(L, -1);
11812 lua_settop(L, 0); /* Empty the stack. */
11813 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +010011814 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010011815 if (msg)
11816 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
11817 else
11818 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
11819 return_status = 0;
11820 break;
11821
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011822 default:
Thierry Fournier670db242020-11-28 10:49:59 +010011823 /* Unknown error */
11824 kind = "Unknown error";
Willy Tarreau14de3952022-11-14 07:08:28 +010011825 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011826 case LUA_YIELD:
11827 /* yield is not configured at this step, this state doesn't happen */
11828 if (!kind)
11829 kind = "yield not allowed";
Willy Tarreau14de3952022-11-14 07:08:28 +010011830 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011831 case LUA_ERRMEM:
11832 if (!kind)
11833 kind = "out of memory error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010011834 lua_settop(L, 0);
11835 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +010011836 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010011837 ha_alert("Lua init: %s: %s\n", kind, trace);
11838 return_status = 0;
11839 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011840 }
Thierry Fournier670db242020-11-28 10:49:59 +010011841 if (!return_status)
11842 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011843 }
Thierry Fournier3c539322020-11-28 16:05:05 +010011844
11845 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +010011846 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011847}
11848
Thierry Fournierb8cef172020-11-28 15:37:17 +010011849int hlua_post_init()
11850{
Thierry Fournier59f11be2020-11-29 00:37:41 +010011851 int ret;
11852 int i;
11853 int errors;
11854 char *err = NULL;
11855 struct hlua_function *fcn;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011856 struct hlua_reg_filter *reg_flt;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011857
Willy Tarreaub1310492021-08-30 09:35:18 +020011858#if defined(USE_OPENSSL)
Thierry Fournierb8cef172020-11-28 15:37:17 +010011859 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010011860 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010011861 int saved_used_backed = global.ssl_used_backend;
11862 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010011863 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +010011864 global.ssl_used_backend = saved_used_backed;
11865 }
11866#endif
11867
Thierry Fournierc7492592020-11-28 23:57:24 +010011868 /* Perform post init of common thread */
11869 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011870 ha_set_thread(&ha_thread_info[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011871 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
11872 if (ret == 0)
11873 return 0;
11874
11875 /* init remaining lua states and load files */
11876 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
11877
11878 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011879 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011880
11881 /* Init lua state */
11882 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
11883
11884 /* Load lua files */
11885 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
11886 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
11887 if (ret != 0) {
11888 ha_alert("Lua init: %s\n", err);
11889 return 0;
11890 }
11891 }
11892 }
11893
11894 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011895 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011896
11897 /* Execute post init for all states */
11898 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
11899
11900 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011901 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011902
11903 /* run post init */
11904 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
11905 if (ret == 0)
11906 return 0;
11907 }
11908
11909 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011910 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011911
11912 /* control functions registering. Each function must have:
11913 * - only the function_ref[0] set positive and all other to -1
11914 * - only the function_ref[0] set to -1 and all other positive
11915 * This ensure a same reference is not used both in shared
11916 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050011917 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +010011918 * complicated to found for the end user.
11919 */
11920 errors = 0;
11921 list_for_each_entry(fcn, &referenced_functions, l) {
11922 ret = 0;
11923 for (i = 1; i < global.nbthread + 1; i++) {
11924 if (fcn->function_ref[i] == -1)
11925 ret--;
11926 else
11927 ret++;
11928 }
11929 if (abs(ret) != global.nbthread) {
11930 ha_alert("Lua function '%s' is not referenced in all thread. "
11931 "Expect function in all thread or in none thread.\n", fcn->name);
11932 errors++;
11933 continue;
11934 }
11935
11936 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050011937 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
11938 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +010011939 "exclusive.\n", fcn->name);
11940 errors++;
11941 }
11942 }
11943
Christopher Faulet69c581a2021-05-31 08:54:04 +020011944 /* Do the same with registered filters */
11945 list_for_each_entry(reg_flt, &referenced_filters, l) {
11946 ret = 0;
11947 for (i = 1; i < global.nbthread + 1; i++) {
11948 if (reg_flt->flt_ref[i] == -1)
11949 ret--;
11950 else
11951 ret++;
11952 }
11953 if (abs(ret) != global.nbthread) {
11954 ha_alert("Lua filter '%s' is not referenced in all thread. "
11955 "Expect function in all thread or in none thread.\n", reg_flt->name);
11956 errors++;
11957 continue;
11958 }
11959
11960 if ((reg_flt->flt_ref[0] == -1) == (ret < 0)) {
11961 ha_alert("Lua filter '%s' is referenced both ins shared Lua context (through lua-load) "
11962 "and per-thread Lua context (through lua-load-per-thread). these two context "
11963 "exclusive.\n", fcn->name);
11964 errors++;
11965 }
11966 }
11967
11968
Thierry Fournier59f11be2020-11-29 00:37:41 +010011969 if (errors > 0)
11970 return 0;
11971
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050011972 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +010011973 * -1 in order to have probably a segfault if someone use it
11974 */
11975 hlua_state_id = -1;
11976
11977 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +010011978}
11979
Willy Tarreau32f61e22015-03-18 17:54:59 +010011980/* The memory allocator used by the Lua stack. <ud> is a pointer to the
11981 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
11982 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010011983 * allocation. <nsize> is the requested new size. A new allocation is
11984 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +010011985 * zero. This one verifies that the limits are respected but is optimized
11986 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreaua5efdff2021-10-22 16:00:02 +020011987 *
11988 * Warning: while this API ressembles glibc's realloc() a lot, glibc surpasses
11989 * POSIX by making realloc(ptr,0) an effective free(), but others do not do
11990 * that and will simply allocate zero as if it were the result of malloc(0),
11991 * so mapping this onto realloc() will lead to memory leaks on non-glibc
11992 * systems.
Willy Tarreau32f61e22015-03-18 17:54:59 +010011993 */
11994static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
11995{
11996 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +010011997 size_t limit, old, new;
11998
11999 /* a limit of ~0 means unlimited and boot complete, so there's no need
12000 * for accounting anymore.
12001 */
Willy Tarreaua5efdff2021-10-22 16:00:02 +020012002 if (likely(~zone->limit == 0)) {
12003 if (!nsize)
12004 ha_free(&ptr);
12005 else
12006 ptr = realloc(ptr, nsize);
12007 return ptr;
12008 }
Willy Tarreau32f61e22015-03-18 17:54:59 +010012009
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010012010 if (!ptr)
12011 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +010012012
Willy Tarreaucdb53462020-12-02 12:12:00 +010012013 /* enforce strict limits across all threads */
12014 limit = zone->limit;
12015 old = _HA_ATOMIC_LOAD(&zone->allocated);
12016 do {
12017 new = old + nsize - osize;
12018 if (unlikely(nsize && limit && new > limit))
12019 return NULL;
12020 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +010012021
Willy Tarreaua5efdff2021-10-22 16:00:02 +020012022 if (!nsize)
12023 ha_free(&ptr);
12024 else
12025 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +010012026
12027 if (unlikely(!ptr && nsize)) // failed
12028 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
12029
12030 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +010012031 return ptr;
12032}
12033
Thierry Fournierecb83c22020-11-28 15:49:44 +010012034/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012035 * We are in the initialisation process of HAProxy, this abort() is
12036 * tolerated.
12037 */
Thierry Fournierecb83c22020-11-28 15:49:44 +010012038lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010012039{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012040 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012041 int idx;
12042 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012043 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012044 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +010012045 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012046 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012047 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012048 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012049
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012050 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012051 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012052
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012053 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012054 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012055 *context = NULL;
12056
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012057 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012058 * the Lua function can fail with an abort. We are in the initialisation
12059 * process of HAProxy, this abort() is tolerated.
12060 */
12061
Thierry Fournier3c539322020-11-28 16:05:05 +010012062 /* Call post initialisation function in safe environment. */
12063 if (setjmp(safe_ljmp_env) != 0) {
12064 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012065 if (lua_type(L, -1) == LUA_TSTRING)
12066 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010012067 else
12068 error_msg = "critical error";
12069 fprintf(stderr, "Lua init: %s.\n", error_msg);
12070 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010012071 } else {
12072 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010012073 }
12074
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012075 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012076 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012077#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
12078#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
12079#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012080 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012081#endif
12082#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012083 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012084#endif
12085#undef HLUA_PREPEND_PATH_TOSTRING
12086#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012087
Thierry Fournier59f11be2020-11-29 00:37:41 +010012088 /* Apply configured prepend path */
12089 list_for_each_entry(pp, &prepend_path_list, l)
12090 hlua_prepend_path(L, pp->type, pp->path);
12091
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012092 /*
12093 *
12094 * Create "core" object.
12095 *
12096 */
12097
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +010012098 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012099 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012100
Thierry Fournierecb83c22020-11-28 15:49:44 +010012101 /* set the thread id */
12102 hlua_class_const_int(L, "thread", thread_num);
12103
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012104 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +010012105 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012106 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012107
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012108 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012109 hlua_class_function(L, "register_init", hlua_register_init);
12110 hlua_class_function(L, "register_task", hlua_register_task);
12111 hlua_class_function(L, "register_fetches", hlua_register_fetches);
12112 hlua_class_function(L, "register_converters", hlua_register_converters);
12113 hlua_class_function(L, "register_action", hlua_register_action);
12114 hlua_class_function(L, "register_service", hlua_register_service);
12115 hlua_class_function(L, "register_cli", hlua_register_cli);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012116 hlua_class_function(L, "register_filter", hlua_register_filter);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012117 hlua_class_function(L, "yield", hlua_yield);
12118 hlua_class_function(L, "set_nice", hlua_set_nice);
12119 hlua_class_function(L, "sleep", hlua_sleep);
12120 hlua_class_function(L, "msleep", hlua_msleep);
12121 hlua_class_function(L, "add_acl", hlua_add_acl);
12122 hlua_class_function(L, "del_acl", hlua_del_acl);
12123 hlua_class_function(L, "set_map", hlua_set_map);
12124 hlua_class_function(L, "del_map", hlua_del_map);
12125 hlua_class_function(L, "tcp", hlua_socket_new);
William Lallemand3956c4e2021-09-21 16:25:15 +020012126 hlua_class_function(L, "httpclient", hlua_httpclient_new);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012127 hlua_class_function(L, "log", hlua_log);
12128 hlua_class_function(L, "Debug", hlua_log_debug);
12129 hlua_class_function(L, "Info", hlua_log_info);
12130 hlua_class_function(L, "Warning", hlua_log_warning);
12131 hlua_class_function(L, "Alert", hlua_log_alert);
12132 hlua_class_function(L, "done", hlua_done);
12133 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012134
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012135 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012136
12137 /*
12138 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012139 * Create "act" object.
12140 *
12141 */
12142
12143 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012144 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012145
12146 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012147 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
12148 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
12149 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
12150 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
12151 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
12152 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
12153 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
12154 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012155
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012156 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010012157
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012158 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012159
12160 /*
12161 *
Christopher Faulet69c581a2021-05-31 08:54:04 +020012162 * Create "Filter" object.
12163 *
12164 */
12165
12166 /* This table entry is the object "filter" base. */
12167 lua_newtable(L);
12168
12169 /* push flags and constants */
12170 hlua_class_const_int(L, "CONTINUE", 1);
12171 hlua_class_const_int(L, "WAIT", 0);
12172 hlua_class_const_int(L, "ERROR", -1);
12173
12174 hlua_class_const_int(L, "FLT_CFG_FL_HTX", FLT_CFG_FL_HTX);
12175
Christopher Fauletc404f112020-02-26 15:03:09 +010012176 hlua_class_function(L, "wake_time", hlua_set_wake_time);
12177 hlua_class_function(L, "register_data_filter", hlua_register_data_filter);
12178 hlua_class_function(L, "unregister_data_filter", hlua_unregister_data_filter);
12179
Christopher Faulet69c581a2021-05-31 08:54:04 +020012180 lua_setglobal(L, "filter");
12181
12182 /*
12183 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012184 * Register class Map
12185 *
12186 */
12187
12188 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012189 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012190
12191 /* register pattern types. */
12192 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012193 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010012194 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012195 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012196 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010012197 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012198
12199 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012200 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012201
12202 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012203 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012204
Ilya Shipitsind4259502020-04-08 01:07:56 +050012205 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012206 lua_pushstring(L, "__index");
12207 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012208
12209 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012210 hlua_class_function(L, "lookup", hlua_map_lookup);
12211 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012212
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012213 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012214
Thierry Fournier45e78d72016-02-19 18:34:46 +010012215 /* Register previous table in the registry with reference and named entry.
12216 * The function hlua_register_metatable() pops the stack, so we
12217 * previously create a copy of the table.
12218 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012219 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
12220 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012221
12222 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012223 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012224
12225 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012226 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012227
12228 /*
12229 *
William Lallemand30fcca12022-03-30 12:03:12 +020012230 * Register "CertCache" class
12231 *
12232 */
12233
12234 /* Create and fill the metatable. */
12235 lua_newtable(L);
12236 /* Register */
12237 hlua_class_function(L, "set", hlua_ckch_set);
12238 lua_setglobal(L, CLASS_CERTCACHE); /* Create global object called Regex */
12239
12240 /*
12241 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012242 * Register class Channel
12243 *
12244 */
12245
12246 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012247 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012248
Ilya Shipitsind4259502020-04-08 01:07:56 +050012249 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012250 lua_pushstring(L, "__index");
12251 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012252
12253 /* Register . */
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012254 hlua_class_function(L, "data", hlua_channel_get_data);
12255 hlua_class_function(L, "line", hlua_channel_get_line);
12256 hlua_class_function(L, "set", hlua_channel_set_data);
12257 hlua_class_function(L, "remove", hlua_channel_del_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012258 hlua_class_function(L, "append", hlua_channel_append);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012259 hlua_class_function(L, "prepend", hlua_channel_prepend);
12260 hlua_class_function(L, "insert", hlua_channel_insert_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012261 hlua_class_function(L, "send", hlua_channel_send);
12262 hlua_class_function(L, "forward", hlua_channel_forward);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012263 hlua_class_function(L, "input", hlua_channel_get_in_len);
12264 hlua_class_function(L, "output", hlua_channel_get_out_len);
12265 hlua_class_function(L, "may_recv", hlua_channel_may_recv);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012266 hlua_class_function(L, "is_full", hlua_channel_is_full);
12267 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012268
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012269 /* Deprecated API */
12270 hlua_class_function(L, "get", hlua_channel_get);
12271 hlua_class_function(L, "dup", hlua_channel_dup);
12272 hlua_class_function(L, "getline", hlua_channel_getline);
12273 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
12274 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
12275
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012276 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012277
12278 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012279 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012280
12281 /*
12282 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012283 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012284 *
12285 */
12286
12287 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012288 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012289
Ilya Shipitsind4259502020-04-08 01:07:56 +050012290 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012291 lua_pushstring(L, "__index");
12292 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012293
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012294 /* Browse existing fetches and create the associated
12295 * object method.
12296 */
12297 sf = NULL;
12298 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012299 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
12300 * by an underscore.
12301 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020012302 strlcpy2(trash.area, sf->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012303 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012304 if (*p == '.' || *p == '-' || *p == '+')
12305 *p = '_';
12306
12307 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012308 lua_pushstring(L, trash.area);
12309 lua_pushlightuserdata(L, sf);
12310 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
12311 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012312 }
12313
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012314 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012315
12316 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012317 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012318
12319 /*
12320 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012321 * Register class Converters
12322 *
12323 */
12324
12325 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012326 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012327
12328 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012329 lua_pushstring(L, "__index");
12330 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012331
12332 /* Browse existing converters and create the associated
12333 * object method.
12334 */
12335 sc = NULL;
12336 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012337 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
12338 * by an underscore.
12339 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020012340 strlcpy2(trash.area, sc->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012341 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012342 if (*p == '.' || *p == '-' || *p == '+')
12343 *p = '_';
12344
12345 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012346 lua_pushstring(L, trash.area);
12347 lua_pushlightuserdata(L, sc);
12348 lua_pushcclosure(L, hlua_run_sample_conv, 1);
12349 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012350 }
12351
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012352 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012353
12354 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012355 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012356
12357 /*
12358 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012359 * Register class HTTP
12360 *
12361 */
12362
12363 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012364 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012365
Ilya Shipitsind4259502020-04-08 01:07:56 +050012366 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012367 lua_pushstring(L, "__index");
12368 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012369
12370 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012371 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
12372 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
12373 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
12374 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
12375 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
12376 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
12377 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
12378 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
12379 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
12380 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012381
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012382 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
12383 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
12384 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
12385 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
12386 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
12387 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
12388 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012389
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012390 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012391
12392 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012393 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012394
Christopher Fauletdf97ac42020-02-26 16:57:19 +010012395 /*
12396 *
12397 * Register class HTTPMessage
12398 *
12399 */
12400
12401 /* Create and fill the metatable. */
12402 lua_newtable(L);
12403
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050012404 /* Create and fill the __index entry. */
Christopher Fauletdf97ac42020-02-26 16:57:19 +010012405 lua_pushstring(L, "__index");
12406 lua_newtable(L);
12407
12408 /* Register Lua functions. */
12409 hlua_class_function(L, "is_resp", hlua_http_msg_is_resp);
12410 hlua_class_function(L, "get_stline", hlua_http_msg_get_stline);
12411 hlua_class_function(L, "get_headers", hlua_http_msg_get_headers);
12412 hlua_class_function(L, "del_header", hlua_http_msg_del_hdr);
12413 hlua_class_function(L, "rep_header", hlua_http_msg_rep_hdr);
12414 hlua_class_function(L, "rep_value", hlua_http_msg_rep_val);
12415 hlua_class_function(L, "add_header", hlua_http_msg_add_hdr);
12416 hlua_class_function(L, "set_header", hlua_http_msg_set_hdr);
12417 hlua_class_function(L, "set_method", hlua_http_msg_set_meth);
12418 hlua_class_function(L, "set_path", hlua_http_msg_set_path);
12419 hlua_class_function(L, "set_query", hlua_http_msg_set_query);
12420 hlua_class_function(L, "set_uri", hlua_http_msg_set_uri);
12421 hlua_class_function(L, "set_status", hlua_http_msg_set_status);
12422 hlua_class_function(L, "is_full", hlua_http_msg_is_full);
12423 hlua_class_function(L, "may_recv", hlua_http_msg_may_recv);
12424 hlua_class_function(L, "eom", hlua_http_msg_is_eom);
12425 hlua_class_function(L, "input", hlua_http_msg_get_in_len);
12426 hlua_class_function(L, "output", hlua_http_msg_get_out_len);
12427
12428 hlua_class_function(L, "body", hlua_http_msg_get_body);
12429 hlua_class_function(L, "set", hlua_http_msg_set_data);
12430 hlua_class_function(L, "remove", hlua_http_msg_del_data);
12431 hlua_class_function(L, "append", hlua_http_msg_append);
12432 hlua_class_function(L, "prepend", hlua_http_msg_prepend);
12433 hlua_class_function(L, "insert", hlua_http_msg_insert_data);
12434 hlua_class_function(L, "set_eom", hlua_http_msg_set_eom);
12435 hlua_class_function(L, "unset_eom", hlua_http_msg_unset_eom);
12436
12437 hlua_class_function(L, "send", hlua_http_msg_send);
12438 hlua_class_function(L, "forward", hlua_http_msg_forward);
12439
12440 lua_rawset(L, -3);
12441
12442 /* Register previous table in the registry with reference and named entry. */
12443 class_http_msg_ref = hlua_register_metatable(L, CLASS_HTTP_MSG);
William Lallemand3956c4e2021-09-21 16:25:15 +020012444
12445 /*
12446 *
12447 * Register class HTTPClient
12448 *
12449 */
12450
12451 /* Create and fill the metatable. */
12452 lua_newtable(L);
12453 lua_pushstring(L, "__index");
12454 lua_newtable(L);
12455 hlua_class_function(L, "get", hlua_httpclient_get);
William Lallemanddc2cc902021-10-26 11:43:26 +020012456 hlua_class_function(L, "head", hlua_httpclient_head);
12457 hlua_class_function(L, "put", hlua_httpclient_put);
12458 hlua_class_function(L, "post", hlua_httpclient_post);
12459 hlua_class_function(L, "delete", hlua_httpclient_delete);
William Lallemand3956c4e2021-09-21 16:25:15 +020012460 lua_settable(L, -3); /* Sets the __index entry. */
William Lallemandf77f1de2021-09-28 19:10:38 +020012461 /* Register the garbage collector entry. */
12462 lua_pushstring(L, "__gc");
12463 lua_pushcclosure(L, hlua_httpclient_gc, 0);
12464 lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
12465
William Lallemand3956c4e2021-09-21 16:25:15 +020012466
12467
12468 class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012469 /*
12470 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012471 * Register class AppletTCP
12472 *
12473 */
12474
12475 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012476 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012477
Ilya Shipitsind4259502020-04-08 01:07:56 +050012478 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012479 lua_pushstring(L, "__index");
12480 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012481
12482 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012483 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
12484 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
12485 hlua_class_function(L, "send", hlua_applet_tcp_send);
12486 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
12487 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
12488 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
12489 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
12490 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012491
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012492 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012493
12494 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012495 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012496
12497 /*
12498 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012499 * Register class AppletHTTP
12500 *
12501 */
12502
12503 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012504 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012505
Ilya Shipitsind4259502020-04-08 01:07:56 +050012506 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012507 lua_pushstring(L, "__index");
12508 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012509
12510 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012511 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
12512 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
12513 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
12514 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
12515 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
12516 hlua_class_function(L, "getline", hlua_applet_http_getline);
12517 hlua_class_function(L, "receive", hlua_applet_http_recv);
12518 hlua_class_function(L, "send", hlua_applet_http_send);
12519 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
12520 hlua_class_function(L, "set_status", hlua_applet_http_status);
12521 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012522
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012523 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012524
12525 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012526 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012527
12528 /*
12529 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012530 * Register class TXN
12531 *
12532 */
12533
12534 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012535 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012536
Ilya Shipitsind4259502020-04-08 01:07:56 +050012537 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012538 lua_pushstring(L, "__index");
12539 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012540
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010012541 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012542 hlua_class_function(L, "set_priv", hlua_set_priv);
12543 hlua_class_function(L, "get_priv", hlua_get_priv);
12544 hlua_class_function(L, "set_var", hlua_set_var);
12545 hlua_class_function(L, "unset_var", hlua_unset_var);
12546 hlua_class_function(L, "get_var", hlua_get_var);
12547 hlua_class_function(L, "done", hlua_txn_done);
12548 hlua_class_function(L, "reply", hlua_txn_reply_new);
12549 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
12550 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
12551 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
12552 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
12553 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
12554 hlua_class_function(L, "deflog", hlua_txn_deflog);
12555 hlua_class_function(L, "log", hlua_txn_log);
12556 hlua_class_function(L, "Debug", hlua_txn_log_debug);
12557 hlua_class_function(L, "Info", hlua_txn_log_info);
12558 hlua_class_function(L, "Warning", hlua_txn_log_warning);
12559 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010012560
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012561 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012562
12563 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012564 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012565
12566 /*
12567 *
Christopher Faulet700d9e82020-01-31 12:21:52 +010012568 * Register class reply
12569 *
12570 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012571 lua_newtable(L);
12572 lua_pushstring(L, "__index");
12573 lua_newtable(L);
12574 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
12575 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
12576 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
12577 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
12578 lua_settable(L, -3); /* Sets the __index entry. */
12579 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +010012580
12581
12582 /*
12583 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012584 * Register class Socket
12585 *
12586 */
12587
12588 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012589 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012590
Ilya Shipitsind4259502020-04-08 01:07:56 +050012591 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012592 lua_pushstring(L, "__index");
12593 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012594
Baptiste Assmann84bb4932015-03-02 21:40:06 +010012595#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012596 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +010012597#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012598 hlua_class_function(L, "connect", hlua_socket_connect);
12599 hlua_class_function(L, "send", hlua_socket_send);
12600 hlua_class_function(L, "receive", hlua_socket_receive);
12601 hlua_class_function(L, "close", hlua_socket_close);
12602 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
12603 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
12604 hlua_class_function(L, "setoption", hlua_socket_setoption);
12605 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012606
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012607 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 the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012610 lua_pushstring(L, "__gc");
12611 lua_pushcclosure(L, hlua_socket_gc, 0);
12612 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012613
12614 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012615 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012616
Thierry Fournieraafc7772020-12-04 11:47:47 +010012617 lua_atpanic(L, hlua_panic_safe);
12618
12619 return L;
12620}
12621
12622void hlua_init(void) {
12623 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012624 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +010012625#ifdef USE_OPENSSL
12626 struct srv_kw *kw;
12627 int tmp_error;
12628 char *error;
12629 char *args[] = { /* SSL client configuration. */
12630 "ssl",
12631 "verify",
12632 "none",
12633 NULL
12634 };
12635#endif
12636
12637 /* Init post init function list head */
12638 for (i = 0; i < MAX_THREADS + 1; i++)
12639 LIST_INIT(&hlua_init_functions[i]);
12640
12641 /* Init state for common/shared lua parts */
12642 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012643 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010012644 hlua_states[0] = hlua_init_state(0);
12645
12646 /* Init state 1 for thread 0. We have at least one thread. */
12647 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012648 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010012649 hlua_states[1] = hlua_init_state(1);
12650
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012651 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +020012652 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012653 if (!socket_proxy) {
12654 fprintf(stderr, "Lua init: %s\n", errmsg);
12655 exit(1);
12656 }
12657 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012658
12659 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012660 socket_tcp = new_server(socket_proxy);
12661 if (!socket_tcp) {
12662 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
12663 exit(1);
12664 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012665
12666#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012667 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012668 socket_ssl = new_server(socket_proxy);
12669 if (!socket_ssl) {
12670 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
12671 exit(1);
12672 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012673
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012674 socket_ssl->use_ssl = 1;
12675 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012676
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000012677 for (i = 0; args[i] != NULL; i++) {
12678 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012679 /*
12680 *
12681 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012682 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012683 * features like client certificates and ssl_verify.
12684 *
12685 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012686 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012687 if (tmp_error != 0) {
12688 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
12689 abort(); /* This must be never arrives because the command line
12690 not editable by the user. */
12691 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000012692 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012693 }
12694 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012695#endif
Thierry Fournier75933d42016-01-21 09:30:18 +010012696
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010012697}
Willy Tarreaubb57d942016-12-21 19:04:56 +010012698
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020012699static void hlua_deinit()
12700{
Willy Tarreau186f3762020-12-04 11:48:12 +010012701 int thr;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012702 struct hlua_reg_filter *reg_flt, *reg_flt_bck;
12703
12704 list_for_each_entry_safe(reg_flt, reg_flt_bck, &referenced_filters, l)
12705 release_hlua_reg_filter(reg_flt);
Willy Tarreau186f3762020-12-04 11:48:12 +010012706
12707 for (thr = 0; thr < MAX_THREADS+1; thr++) {
12708 if (hlua_states[thr])
12709 lua_close(hlua_states[thr]);
12710 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +010012711
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020012712 srv_drop(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +010012713
Willy Tarreau0f143af2021-03-05 10:41:48 +010012714#ifdef USE_OPENSSL
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020012715 srv_drop(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +010012716#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012717
12718 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020012719}
12720
12721REGISTER_POST_DEINIT(hlua_deinit);
12722
Willy Tarreau80713382018-11-26 10:19:54 +010012723static void hlua_register_build_options(void)
12724{
Willy Tarreaubb57d942016-12-21 19:04:56 +010012725 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +010012726
Willy Tarreaubb57d942016-12-21 19:04:56 +010012727 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
12728 hap_register_build_opts(ptr, 1);
12729}
Willy Tarreau80713382018-11-26 10:19:54 +010012730
12731INITCALL0(STG_REGISTER, hlua_register_build_options);