blob: bc7fbe02042242764bb2791fc4d0dd5e4a9de3c3 [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>
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +010068#include <haproxy/event_hdl.h>
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +020069#include <haproxy/check.h>
Aurelien DARRAGON5bed48f2023-04-21 17:32:46 +020070#include <haproxy/mailers.h>
Thierry FOURNIER380d0932015-01-23 14:27:52 +010071
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010072/* Lua uses longjmp to perform yield or throwing errors. This
73 * macro is used only for identifying the function that can
74 * not return because a longjmp is executed.
75 * __LJMP marks a prototype of hlua file that can use longjmp.
76 * WILL_LJMP() marks an lua function that will use longjmp.
77 * MAY_LJMP() marks an lua function that may use longjmp.
78 */
79#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020080#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010081#define MAY_LJMP(func) func
82
Thierry FOURNIERbabae282015-09-17 11:36:37 +020083/* This couple of function executes securely some Lua calls outside of
84 * the lua runtime environment. Each Lua call can return a longjmp
85 * if it encounter a memory error.
86 *
87 * Lua documentation extract:
88 *
89 * If an error happens outside any protected environment, Lua calls
90 * a panic function (see lua_atpanic) and then calls abort, thus
91 * exiting the host application. Your panic function can avoid this
92 * exit by never returning (e.g., doing a long jump to your own
93 * recovery point outside Lua).
94 *
95 * The panic function runs as if it were a message handler (see
Willy Tarreau3dfb7da2022-03-02 22:33:39 +010096 * #2.3); in particular, the error message is at the top of the
Thierry FOURNIERbabae282015-09-17 11:36:37 +020097 * stack. However, there is no guarantee about stack space. To push
98 * anything on the stack, the panic function must first check the
Willy Tarreau3dfb7da2022-03-02 22:33:39 +010099 * available space (see #4.2).
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200100 *
101 * We must check all the Lua entry point. This includes:
102 * - The include/proto/hlua.h exported functions
103 * - the task wrapper function
104 * - The action wrapper function
105 * - The converters wrapper function
106 * - The sample-fetch wrapper functions
107 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500108 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800109 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200110 *
111 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
112 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
113 * because they must be exists in the program stack when the longjmp
114 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200115 *
116 * Note that the Lua processing is not really thread safe. It provides
117 * heavy system which consists to add our own lock function in the Lua
118 * code and recompile the library. This system will probably not accepted
119 * by maintainers of various distribs.
120 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500121 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200122 * quick looking on the Lua sources displays a lua_lock() a the start
123 * of function and a lua_unlock() at the end of the function. So I
124 * conclude that the Lua thread safe mode just perform a mutex around
125 * all execution. So I prefer to do this in the HAProxy code, it will be
126 * easier for distro maintainers.
127 *
128 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
129 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
130 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200131 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100132__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200133THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200134static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau6a510902021-07-14 19:41:25 +0200135static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); return 0; }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200136
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100137/* This is the chained list of struct hlua_function referenced
138 * for haproxy action, sample-fetches, converters, cli and
139 * applet bindings. It is used for a post-initialisation control.
140 */
141static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
142
Thierry Fournierc7492592020-11-28 23:57:24 +0100143/* This variable is used only during initialization to identify the Lua state
144 * currently being initialized. 0 is the common lua state, 1 to n are the Lua
145 * states dedicated to each thread (in this case hlua_state_id==tid+1).
146 */
147static int hlua_state_id;
148
Thierry Fournier59f11be2020-11-29 00:37:41 +0100149/* This is a NULL-terminated list of lua file which are referenced to load per thread */
Thierry Fournierae6b5682022-09-19 09:04:16 +0200150static char ***per_thread_load = NULL;
Thierry Fournier59f11be2020-11-29 00:37:41 +0100151
152lua_State *hlua_init_state(int thread_id);
153
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200154/* This function takes the Lua global lock. Keep this function's visibility
155 * global so that it can appear in stack dumps and performance profiles!
156 */
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100157static inline void lua_take_global_lock()
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200158{
159 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
160}
161
162static inline void lua_drop_global_lock()
163{
164 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
165}
166
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +0100167/* lua lock helpers: only lock when required
168 *
169 * state_id == 0: we're operating on the main lua stack (shared between
170 * os threads), so we need to acquire the main lock
171 *
172 * If the thread already owns the lock (_hlua_locked != 0), skip the lock
173 * attempt. This could happen if we run under protected lua environment.
174 * Not doing this could result in deadlocks because of nested locking
175 * attempts from the same thread
176 */
177static THREAD_LOCAL int _hlua_locked = 0;
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100178static inline void hlua_lock(struct hlua *hlua)
179{
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +0100180 if (hlua->state_id != 0)
181 return;
182 if (!_hlua_locked)
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100183 lua_take_global_lock();
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +0100184 _hlua_locked += 1;
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100185}
186static inline void hlua_unlock(struct hlua *hlua)
187{
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +0100188 if (hlua->state_id != 0)
189 return;
190 BUG_ON(_hlua_locked <= 0);
191 _hlua_locked--;
192 /* drop the lock once the lock count reaches 0 */
193 if (!_hlua_locked)
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100194 lua_drop_global_lock();
195}
196
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100197#define SET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200198 ({ \
199 int ret; \
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100200 hlua_lock(__HLUA); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200201 if (setjmp(safe_ljmp_env) != 0) { \
202 lua_atpanic(__L, hlua_panic_safe); \
203 ret = 0; \
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100204 hlua_unlock(__HLUA); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200205 } else { \
206 lua_atpanic(__L, hlua_panic_ljmp); \
207 ret = 1; \
208 } \
209 ret; \
210 })
211
212/* If we are the last function catching Lua errors, we
213 * must reset the panic function.
214 */
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100215#define RESET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200216 do { \
217 lua_atpanic(__L, hlua_panic_safe); \
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100218 hlua_unlock(__HLUA); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200219 } while(0)
220
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100221#define SET_SAFE_LJMP(__HLUA) \
222 SET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
223
224#define RESET_SAFE_LJMP(__HLUA) \
225 RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
226
227#define SET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100228 SET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100229
230#define RESET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100231 RESET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100232
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200233/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200234#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100235/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200236#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200237/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100238#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100239#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200240
Thierry Fournierafc63e22020-11-28 17:06:51 +0100241/* The main Lua execution context. The 0 index is the
242 * common state shared by all threads.
243 */
Willy Tarreau186f3762020-12-04 11:48:12 +0100244static lua_State *hlua_states[MAX_THREADS + 1];
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100245
Christopher Fauletc404f112020-02-26 15:03:09 +0100246#define HLUA_FLT_CB_FINAL 0x00000001
247#define HLUA_FLT_CB_RETVAL 0x00000002
248#define HLUA_FLT_CB_ARG_CHN 0x00000004
249#define HLUA_FLT_CB_ARG_HTTP_MSG 0x00000008
250
Christopher Faulet9f55a502020-02-25 15:21:02 +0100251#define HLUA_FLT_CTX_FL_PAYLOAD 0x00000001
252
Christopher Faulet69c581a2021-05-31 08:54:04 +0200253struct hlua_reg_filter {
254 char *name;
255 int flt_ref[MAX_THREADS + 1];
256 int fun_ref[MAX_THREADS + 1];
257 struct list l;
258};
259
260struct hlua_flt_config {
261 struct hlua_reg_filter *reg;
262 int ref[MAX_THREADS + 1];
263 char **args;
264};
265
266struct hlua_flt_ctx {
267 int ref; /* ref to the filter lua object */
268 struct hlua *hlua[2]; /* lua runtime context (0: request, 1: response) */
269 unsigned int cur_off[2]; /* current offset (0: request, 1: response) */
270 unsigned int cur_len[2]; /* current forwardable length (0: request, 1: response) */
271 unsigned int flags; /* HLUA_FLT_CTX_FL_* */
272};
273
Willy Tarreau5321da92022-05-06 11:57:34 +0200274/* appctx context used by the cosockets */
275struct hlua_csk_ctx {
276 int connected;
277 struct xref xref; /* cross reference with the Lua object owner. */
278 struct list wake_on_read;
279 struct list wake_on_write;
280 struct appctx *appctx;
281 int die;
282};
283
Willy Tarreaue23f33b2022-05-06 14:07:13 +0200284/* appctx context used by TCP services */
285struct hlua_tcp_ctx {
286 struct hlua *hlua;
287 int flags;
288 struct task *task;
289};
290
Willy Tarreauaa229cc2022-05-06 14:26:10 +0200291/* appctx context used by HTTP services */
292struct hlua_http_ctx {
293 struct hlua *hlua;
294 int left_bytes; /* The max amount of bytes that we can read. */
295 int flags;
296 int status;
297 const char *reason;
298 struct task *task;
299};
300
Willy Tarreaubcda5f62022-05-03 18:13:39 +0200301/* used by registered CLI keywords */
302struct hlua_cli_ctx {
303 struct hlua *hlua;
304 struct task *task;
305 struct hlua_function *fcn;
306};
307
Christopher Faulet69c581a2021-05-31 08:54:04 +0200308DECLARE_STATIC_POOL(pool_head_hlua_flt_ctx, "hlua_flt_ctx", sizeof(struct hlua_flt_ctx));
309
Christopher Faulet9f55a502020-02-25 15:21:02 +0100310static int hlua_filter_from_payload(struct filter *filter);
311
Christopher Faulet69c581a2021-05-31 08:54:04 +0200312/* This is the chained list of struct hlua_flt referenced
313 * for haproxy filters. It is used for a post-initialisation control.
314 */
315static struct list referenced_filters = LIST_HEAD_INIT(referenced_filters);
316
317
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100318/* This is the memory pool containing struct lua for applets
319 * (including cli).
320 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100321DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100322
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100323/* Used for Socket connection. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +0100324static struct proxy *socket_proxy;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100325static struct server *socket_tcp;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100326#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100327static struct server *socket_ssl;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100328#endif
329
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100330/* List head of the function called at the initialisation time. */
Thierry Fournierc7492592020-11-28 23:57:24 +0100331struct list hlua_init_functions[MAX_THREADS + 1];
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100332
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100333/* The following variables contains the reference of the different
334 * Lua classes. These references are useful for identify metadata
335 * associated with an object.
336 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100337static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100338static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100339static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100340static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100341static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100342static int class_http_ref;
Christopher Fauletdf97ac42020-02-26 16:57:19 +0100343static int class_http_msg_ref;
William Lallemand3956c4e2021-09-21 16:25:15 +0200344static int class_httpclient_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200345static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200346static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200347static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100348static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100349
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +0100350/* Lua max execution timeouts. By default, stream-related
351 * lua coroutines (e.g.: actions) have a short timeout.
352 * On the other hand tasks coroutines don't have a timeout because
353 * a task may remain alive during all the haproxy execution.
354 *
355 * Timeouts are expressed in milliseconds, they are meant to be used
356 * with hlua timer's API exclusively.
357 * 0 means no timeout
358 */
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +0200359static uint32_t hlua_timeout_burst = 1000; /* burst timeout. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +0100360static uint32_t hlua_timeout_session = 4000; /* session timeout. */
361static uint32_t hlua_timeout_task = 0; /* task timeout. */
362static uint32_t hlua_timeout_applet = 4000; /* applet timeout. */
363
364/* hlua multipurpose timer:
365 * used to compute burst lua time (within a single hlua_ctx_resume())
366 * and cumulative lua time for a given coroutine, and to check
367 * the lua coroutine against the configured timeouts
368 */
369
370/* fetch per-thread cpu_time with ms precision (may wrap) */
371static inline uint32_t _hlua_time_ms()
372{
373 /* We're interested in the current cpu time in ms, which will be returned
374 * as a uint32_t to save some space.
375 * We must take the following into account:
376 *
377 * - now_cpu_time_fast() which returns the time in nanoseconds as a uint64_t
378 * will wrap every 585 years.
379 * - uint32_t may only contain 4294967295ms (~=49.7 days), so _hlua_time_ms()
380 * itself will also wrap every 49.7 days.
381 *
382 * While we can safely ignore the now_cpu_time_fast() wrap, we must
383 * take care of the uint32_t wrap by making sure to exclusively
384 * manipulate the time using uint32_t everywhere _hlua_time_ms()
385 * is involved.
386 */
387 return (uint32_t)(now_cpu_time_fast() / 1000000ULL);
388}
389
390/* computes time spent in a single lua execution (in ms) */
391static inline uint32_t _hlua_time_burst(const struct hlua_timer *timer)
392{
393 uint32_t burst_ms;
394
395 /* wrapping is expected and properly
396 * handled thanks to _hlua_time_ms() and burst_ms
397 * being of the same type
398 */
399 burst_ms = _hlua_time_ms() - timer->start;
400 return burst_ms;
401}
402
403static inline void hlua_timer_init(struct hlua_timer *timer, unsigned int max)
404{
405 timer->cumulative = 0;
406 timer->burst = 0;
407 timer->max = max;
408}
409
410/* reset the timer ctx between 2 yields */
411static inline void hlua_timer_reset(struct hlua_timer *timer)
412{
413 timer->cumulative += timer->burst;
414 timer->burst = 0;
415}
416
417/* start the timer right before a new execution */
418static inline void hlua_timer_start(struct hlua_timer *timer)
419{
420 timer->start = _hlua_time_ms();
421}
422
423/* update hlua timer when finishing an execution */
424static inline void hlua_timer_stop(struct hlua_timer *timer)
425{
426 timer->burst += _hlua_time_burst(timer);
427}
428
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +0200429/* check the timers for current hlua context:
430 * - first check for burst timeout (max execution time for the current
431 hlua resume, ie: time between effective yields)
432 * - then check for yield cumulative timeout
433 *
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +0100434 * Returns 1 if the check succeeded and 0 if it failed
435 * (ie: timeout exceeded)
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100436 */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +0100437static inline int hlua_timer_check(const struct hlua_timer *timer)
438{
439 uint32_t pburst = _hlua_time_burst(timer); /* pending burst time in ms */
440
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +0200441 if (hlua_timeout_burst && (timer->burst + pburst) > hlua_timeout_burst)
442 return 0; /* burst timeout exceeded */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +0100443 if (timer->max && (timer->cumulative + timer->burst + pburst) > timer->max)
444 return 0; /* cumulative timeout exceeded */
445 return 1; /* ok */
446}
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100447
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100448/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
449 * it is used for preventing infinite loops.
450 *
451 * I test the scheer with an infinite loop containing one incrementation
452 * and one test. I run this loop between 10 seconds, I raise a ceil of
453 * 710M loops from one interrupt each 9000 instructions, so I fix the value
454 * to one interrupt each 10 000 instructions.
455 *
456 * configured | Number of
457 * instructions | loops executed
458 * between two | in milions
459 * forced yields |
460 * ---------------+---------------
461 * 10 | 160
462 * 500 | 670
463 * 1000 | 680
464 * 5000 | 700
465 * 7000 | 700
466 * 8000 | 700
467 * 9000 | 710 <- ceil
468 * 10000 | 710
469 * 100000 | 710
470 * 1000000 | 710
471 *
472 */
473static unsigned int hlua_nb_instruction = 10000;
474
Willy Tarreaucdb53462020-12-02 12:12:00 +0100475/* Descriptor for the memory allocation state. The limit is pre-initialised to
476 * 0 until it is replaced by "tune.lua.maxmem" during the config parsing, or it
477 * is replaced with ~0 during post_init after everything was loaded. This way
478 * it is guaranteed that if limit is ~0 the boot is complete and that if it's
479 * zero it's not yet limited and proper accounting is required.
Willy Tarreau32f61e22015-03-18 17:54:59 +0100480 */
481struct hlua_mem_allocator {
482 size_t allocated;
483 size_t limit;
484};
485
Willy Tarreaucdb53462020-12-02 12:12:00 +0100486static struct hlua_mem_allocator hlua_global_allocator THREAD_ALIGNED(64);
Willy Tarreau32f61e22015-03-18 17:54:59 +0100487
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +0100488/* hlua event subscription */
489struct hlua_event_sub {
490 int fcn_ref;
491 int state_id;
492 struct hlua *hlua;
493 struct task *task;
494 event_hdl_async_equeue equeue;
495 struct event_hdl_sub *sub;
496 uint8_t paused;
497};
498
499/* This is the memory pool containing struct hlua_event_sub
500 * for event subscriptions from lua
501 */
502DECLARE_STATIC_POOL(pool_head_hlua_event_sub, "hlua_esub", sizeof(struct hlua_event_sub));
503
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100504/* These functions converts types between HAProxy internal args or
505 * sample and LUA types. Another function permits to check if the
506 * LUA stack contains arguments according with an required ARG_T
507 * format.
508 */
Aurelien DARRAGONe5c048a2023-05-17 10:51:50 +0200509__LJMP static int hlua_arg2lua(lua_State *L, const struct arg *arg);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100510static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100511__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100512 uint64_t mask, struct proxy *p);
Aurelien DARRAGON41217722023-05-17 10:44:47 +0200513__LJMP static int hlua_smp2lua(lua_State *L, struct sample *smp);
Aurelien DARRAGON742b1a82023-05-17 10:38:50 +0200514__LJMP static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100515static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
516
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100517__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200518
Thierry Fournier59f11be2020-11-29 00:37:41 +0100519struct prepend_path {
520 struct list l;
521 char *type;
522 char *path;
523};
524
525static struct list prepend_path_list = LIST_HEAD_INIT(prepend_path_list);
526
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200527#define SEND_ERR(__be, __fmt, __args...) \
528 do { \
529 send_log(__be, LOG_ERR, __fmt, ## __args); \
530 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100531 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200532 } while (0)
533
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100534static inline struct hlua_function *new_hlua_function()
535{
536 struct hlua_function *fcn;
Thierry Fournierc7492592020-11-28 23:57:24 +0100537 int i;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100538
539 fcn = calloc(1, sizeof(*fcn));
540 if (!fcn)
541 return NULL;
Willy Tarreau2b718102021-04-21 07:32:39 +0200542 LIST_APPEND(&referenced_functions, &fcn->l);
Thierry Fournierc7492592020-11-28 23:57:24 +0100543 for (i = 0; i < MAX_THREADS + 1; i++)
544 fcn->function_ref[i] = -1;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100545 return fcn;
546}
547
Christopher Fauletdda44442021-04-12 14:05:43 +0200548static inline void release_hlua_function(struct hlua_function *fcn)
549{
550 if (!fcn)
551 return;
552 if (fcn->name)
553 ha_free(&fcn->name);
Willy Tarreau2b718102021-04-21 07:32:39 +0200554 LIST_DELETE(&fcn->l);
Christopher Fauletdda44442021-04-12 14:05:43 +0200555 ha_free(&fcn);
556}
557
Thierry Fournierc7492592020-11-28 23:57:24 +0100558/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
559static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
560{
561 if (fcn->function_ref[0] == -1)
562 return tid + 1;
563 return 0;
564}
565
Christopher Faulet69c581a2021-05-31 08:54:04 +0200566/* Create a new registered filter. Only its name is filled */
567static inline struct hlua_reg_filter *new_hlua_reg_filter(const char *name)
568{
569 struct hlua_reg_filter *reg_flt;
570 int i;
571
572 reg_flt = calloc(1, sizeof(*reg_flt));
573 if (!reg_flt)
574 return NULL;
575 reg_flt->name = strdup(name);
576 if (!reg_flt->name) {
577 free(reg_flt);
578 return NULL;
579 }
580 LIST_APPEND(&referenced_filters, &reg_flt->l);
581 for (i = 0; i < MAX_THREADS + 1; i++) {
582 reg_flt->flt_ref[i] = -1;
583 reg_flt->fun_ref[i] = -1;
584 }
585 return reg_flt;
586}
587
588/* Release a registered filter */
589static inline void release_hlua_reg_filter(struct hlua_reg_filter *reg_flt)
590{
591 if (!reg_flt)
592 return;
593 if (reg_flt->name)
594 ha_free(&reg_flt->name);
595 LIST_DELETE(&reg_flt->l);
596 ha_free(&reg_flt);
597}
598
599/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
600static inline int reg_flt_to_stack_id(struct hlua_reg_filter *reg_flt)
601{
602 if (reg_flt->fun_ref[0] == -1)
603 return tid + 1;
604 return 0;
605}
606
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100607/* Used to check an Lua function type in the stack. It creates and
608 * returns a reference of the function. This function throws an
Aurelien DARRAGONf8f8a2b2023-03-02 17:50:49 +0100609 * error if the argument is not a "function".
610 * When no longer used, the ref must be released with hlua_unref()
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100611 */
Aurelien DARRAGON9ee0d042023-03-20 18:36:08 +0100612__LJMP int hlua_checkfunction(lua_State *L, int argno)
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100613{
614 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100615 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100616 WILL_LJMP(luaL_argerror(L, argno, msg));
617 }
618 lua_pushvalue(L, argno);
619 return luaL_ref(L, LUA_REGISTRYINDEX);
620}
621
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100622/* Used to check an Lua table type in the stack. It creates and
623 * returns a reference of the table. This function throws an
Aurelien DARRAGONf8f8a2b2023-03-02 17:50:49 +0100624 * error if the argument is not a "table".
625 * When no longer used, the ref must be released with hlua_unref()
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100626 */
Aurelien DARRAGON9ee0d042023-03-20 18:36:08 +0100627__LJMP int hlua_checktable(lua_State *L, int argno)
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100628{
629 if (!lua_istable(L, argno)) {
630 const char *msg = lua_pushfstring(L, "table expected, got %s", luaL_typename(L, argno));
631 WILL_LJMP(luaL_argerror(L, argno, msg));
632 }
633 lua_pushvalue(L, argno);
634 return luaL_ref(L, LUA_REGISTRYINDEX);
635}
636
Aurelien DARRAGONf8f8a2b2023-03-02 17:50:49 +0100637/* Get a reference to the object that is at the top of the stack
638 * The referenced object will be popped from the stack
639 *
640 * The function returns the reference to the object which must
641 * be cleared using hlua_unref() when no longer used
642 */
643__LJMP int hlua_ref(lua_State *L)
644{
645 return MAY_LJMP(luaL_ref(L, LUA_REGISTRYINDEX));
646}
647
648/* Pushes a reference previously created using luaL_ref(L, LUA_REGISTRYINDEX)
649 * on <L> stack
650 * (ie: hlua_checkfunction(), hlua_checktable() or hlua_ref())
651 *
652 * When the reference is no longer used, it should be released by calling
653 * hlua_unref()
654 *
655 * <L> can be from any co-routine as long as it belongs to the same lua
656 * parent state that the one used to get the reference.
657 */
658void hlua_pushref(lua_State *L, int ref)
659{
660 lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
661}
662
663/* Releases a reference previously created using luaL_ref(L, LUA_REGISTRYINDEX)
664 * (ie: hlua_checkfunction(), hlua_checktable() or hlua_ref())
665 *
666 * This will allow the reference to be reused and the referred object
667 * to be garbage collected.
668 *
669 * <L> can be from any co-routine as long as it belongs to the same lua
670 * parent state that the one used to get the reference.
671 */
672void hlua_unref(lua_State *L, int ref)
673{
674 luaL_unref(L, LUA_REGISTRYINDEX, ref);
675}
676
Christopher Fauletd09cc512021-03-24 14:48:45 +0100677__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200678{
679 lua_Debug ar;
680 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200681 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200682
683 while (lua_getstack(L, level++, &ar)) {
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200684 /* Fill fields:
685 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
686 * 'l': fills in the field currentline;
687 * 'n': fills in the field name and namewhat;
688 * 't': fills in the field istailcall;
689 */
690 lua_getinfo(L, "Slnt", &ar);
691
Willy Tarreau5c143402022-06-19 17:35:53 +0200692 /* skip these empty entries, usually they come from deep C functions */
693 if (ar.currentline < 0 && *ar.what == 'C' && !*ar.namewhat && !ar.name)
694 continue;
695
696 /* Add separator */
697 if (b_data(msg))
698 chunk_appendf(msg, "%s", sep);
699
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200700 /* Append code localisation */
701 if (ar.currentline > 0)
Christopher Fauletd09cc512021-03-24 14:48:45 +0100702 chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200703 else
Christopher Fauletd09cc512021-03-24 14:48:45 +0100704 chunk_appendf(msg, "%s: ", ar.short_src);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200705
706 /*
707 * Get function name
708 *
709 * if namewhat is no empty, name is defined.
710 * what contains "Lua" for Lua function, "C" for C function,
711 * or "main" for main code.
712 */
713 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100714 chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200715
716 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100717 chunk_appendf(msg, "in main chunk");
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200718
719 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100720 chunk_appendf(msg, "in function line %d", ar.linedefined);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200721
722 else /* nothing left... */
723 chunk_appendf(msg, "?");
724
725
726 /* Display tailed call */
727 if (ar.istailcall)
728 chunk_appendf(msg, " ...");
729 }
730
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200731 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200732}
733
734
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100735/* This function check the number of arguments available in the
736 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500737 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100738 */
739__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
740{
741 if (lua_gettop(L) == nb)
742 return;
743 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
744}
745
Mark Lakes22154b42018-01-29 14:38:40 -0800746/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100747 * and the line number where the error is encountered.
748 */
749static int hlua_pusherror(lua_State *L, const char *fmt, ...)
750{
751 va_list argp;
752 va_start(argp, fmt);
753 luaL_where(L, 1);
754 lua_pushvfstring(L, fmt, argp);
755 va_end(argp);
756 lua_concat(L, 2);
757 return 1;
758}
759
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100760/* This functions is used with sample fetch and converters. It
761 * converts the HAProxy configuration argument in a lua stack
762 * values.
763 *
764 * It takes an array of "arg", and each entry of the array is
765 * converted and pushed in the LUA stack.
766 */
Aurelien DARRAGONe5c048a2023-05-17 10:51:50 +0200767__LJMP static int hlua_arg2lua(lua_State *L, const struct arg *arg)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100768{
769 switch (arg->type) {
770 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100771 case ARGT_TIME:
772 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100773 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100774 break;
775
776 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200777 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100778 break;
779
780 case ARGT_IPV4:
781 case ARGT_IPV6:
782 case ARGT_MSK4:
783 case ARGT_MSK6:
784 case ARGT_FE:
785 case ARGT_BE:
786 case ARGT_TAB:
787 case ARGT_SRV:
788 case ARGT_USR:
789 case ARGT_MAP:
790 default:
791 lua_pushnil(L);
792 break;
793 }
794 return 1;
795}
796
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500797/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100798 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500799 * with sample fetch wrappers. The input arguments are given to the
800 * lua wrapper and converted as arg list by the function.
Aurelien DARRAGON0aaf6c42023-05-17 15:33:59 +0200801 *
802 * Note: although lua_tolstring() may raise a memory error according to
803 * lua documentation, in practise this could only happen when using to
804 * use lua_tolstring() on a number (lua will try to push the number as a
805 * string on the stack, and this may result in memory failure), so here we
806 * assume that hlua_lua2arg() will never raise an exception since it is
807 * exclusively used with lua string inputs.
808 *
809 * Note2: You should be extra careful when using <arg> argument, since
810 * string arguments rely on lua_tolstring() which returns a pointer to lua
811 * object that may be garbage collected at any time when removed from lua
812 * stack, thus you should make sure that <arg> is only used from a local
813 * scope within lua context (and not exported or stored in a lua-independent
814 * ctx) and that related lua object still exists when accessing arg data.
815 * See: https://www.lua.org/manual/5.4/manual.html#4.1.3
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100816 */
817static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
818{
819 switch (lua_type(L, ud)) {
820
821 case LUA_TNUMBER:
822 case LUA_TBOOLEAN:
823 arg->type = ARGT_SINT;
824 arg->data.sint = lua_tointeger(L, ud);
825 break;
826
827 case LUA_TSTRING:
828 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200829 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200830 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200831 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200832 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100833 break;
834
835 case LUA_TUSERDATA:
836 case LUA_TNIL:
837 case LUA_TTABLE:
838 case LUA_TFUNCTION:
839 case LUA_TTHREAD:
840 case LUA_TLIGHTUSERDATA:
841 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200842 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100843 break;
844 }
845 return 1;
846}
847
848/* the following functions are used to convert a struct sample
849 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500850 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100851 */
Aurelien DARRAGON41217722023-05-17 10:44:47 +0200852__LJMP static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100853{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200854 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100855 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100856 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200857 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100858 break;
859
860 case SMP_T_BIN:
861 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200862 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100863 break;
864
865 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200866 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100867 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
868 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
869 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
870 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
871 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
872 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
873 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
874 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
875 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200876 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100877 break;
878 default:
879 lua_pushnil(L);
880 break;
881 }
882 break;
883
884 case SMP_T_IPV4:
885 case SMP_T_IPV6:
886 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200887 if (sample_casts[smp->data.type][SMP_T_STR] &&
888 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200889 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100890 else
891 lua_pushnil(L);
892 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100893 default:
894 lua_pushnil(L);
895 break;
896 }
897 return 1;
898}
899
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100900/* the following functions are used to convert a struct sample
901 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500902 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100903 */
Aurelien DARRAGON742b1a82023-05-17 10:38:50 +0200904__LJMP static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100905{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200906 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100907
908 case SMP_T_BIN:
909 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200910 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100911 break;
912
913 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200914 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100915 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
916 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
917 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
918 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
919 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
920 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
921 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
922 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
923 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200924 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100925 break;
926 default:
927 lua_pushstring(L, "");
928 break;
929 }
930 break;
931
932 case SMP_T_SINT:
933 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100934 case SMP_T_IPV4:
935 case SMP_T_IPV6:
936 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200937 if (sample_casts[smp->data.type][SMP_T_STR] &&
938 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200939 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100940 else
941 lua_pushstring(L, "");
942 break;
943 default:
944 lua_pushstring(L, "");
945 break;
946 }
947 return 1;
948}
949
Aurelien DARRAGONa3624cb2023-05-17 15:44:45 +0200950/* The following function is used to convert a Lua type to a
951 * struct sample. This is useful to provide data from LUA code to
952 * a converter.
953 *
954 * Note: although lua_tolstring() may raise a memory error according to
955 * lua documentation, in practise this could only happen when using to
956 * use lua_tolstring() on a number (lua will try to push the number as a
957 * string on the stack, and this may result in memory failure), so here we
958 * assume that hlua_lua2arg() will never raise an exception since it is
959 * exclusively used with lua string inputs.
960 *
961 * Note2: You should be extra careful when using <smp> argument, since
962 * string arguments rely on lua_tolstring() which returns a pointer to lua
963 * object that may be garbage collected at any time when removed from lua
964 * stack, thus you should make sure that <smp> is only used from a local
965 * scope within lua context (not exported or stored in a lua-independent
966 * ctx) and that related lua object still exists when accessing arg data.
967 * See: https://www.lua.org/manual/5.4/manual.html#4.1.3
968 *
969 * If you don't comply with this usage restriction, then you should consider
970 * duplicating the smp using smp_dup() to make it portable (little overhead),
971 * as this will ensure that the smp always points to valid memory block.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100972 */
973static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
974{
975 switch (lua_type(L, ud)) {
976
977 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200978 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200979 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100980 break;
981
982
983 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200984 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200985 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100986 break;
987
988 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200989 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100990 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200991 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200992 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200993 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200994 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100995 break;
996
997 case LUA_TUSERDATA:
998 case LUA_TNIL:
999 case LUA_TTABLE:
1000 case LUA_TFUNCTION:
1001 case LUA_TTHREAD:
1002 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +02001003 case LUA_TNONE:
1004 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001005 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001006 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001007 break;
1008 }
1009 return 1;
1010}
1011
Ilya Shipitsind4259502020-04-08 01:07:56 +05001012/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001013 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001014 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001015 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001016 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Willy Tarreauee0d7272021-07-16 10:26:56 +02001017 * entries and that there is at least one stop at the last position.
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001018 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001019__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +01001020 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001021{
1022 int min_arg;
Willy Tarreauee0d7272021-07-16 10:26:56 +02001023 int idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001024 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +02001025 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +02001026 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001027 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +02001028 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001029
1030 idx = 0;
1031 min_arg = ARGM(mask);
1032 mask >>= ARGM_BITS;
1033
1034 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001035 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001036
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001037 /* Check for mandatory arguments. */
1038 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001039 if (idx < min_arg) {
1040
1041 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001042 if (idx > 0) {
1043 msg = "Mandatory argument expected";
1044 goto error;
1045 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001046
1047 /* If first argument have a certain type, some default values
1048 * may be used. See the function smp_resolve_args().
1049 */
1050 switch (mask & ARGT_MASK) {
1051
1052 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001053 if (!(p->cap & PR_CAP_FE)) {
1054 msg = "Mandatory argument expected";
1055 goto error;
1056 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001057 argp[idx].data.prx = p;
1058 argp[idx].type = ARGT_FE;
1059 argp[idx+1].type = ARGT_STOP;
1060 break;
1061
1062 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001063 if (!(p->cap & PR_CAP_BE)) {
1064 msg = "Mandatory argument expected";
1065 goto error;
1066 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001067 argp[idx].data.prx = p;
1068 argp[idx].type = ARGT_BE;
1069 argp[idx+1].type = ARGT_STOP;
1070 break;
1071
1072 case ARGT_TAB:
Olivier Houchard14f62682022-09-13 00:35:53 +02001073 if (!p->table) {
1074 msg = "Mandatory argument expected";
1075 goto error;
1076 }
1077 argp[idx].data.t = p->table;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001078 argp[idx].type = ARGT_TAB;
1079 argp[idx+1].type = ARGT_STOP;
1080 break;
1081
1082 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001083 msg = "Mandatory argument expected";
1084 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +01001085 break;
1086 }
1087 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001088 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001089 }
1090
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001091 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001092 if ((mask & ARGT_MASK) == ARGT_STOP &&
1093 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001094 msg = "Last argument expected";
1095 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001096 }
1097
1098 if ((mask & ARGT_MASK) == ARGT_STOP &&
1099 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001100 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001101 }
1102
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001103 /* Convert some argument types. All string in argp[] are for not
1104 * duplicated yet.
1105 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001106 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001107 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001108 if (argp[idx].type != ARGT_SINT) {
1109 msg = "integer expected";
1110 goto error;
1111 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001112 argp[idx].type = ARGT_SINT;
1113 break;
1114
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001115 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001116 if (argp[idx].type != ARGT_SINT) {
1117 msg = "integer expected";
1118 goto error;
1119 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +02001120 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001121 break;
1122
1123 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001124 if (argp[idx].type != ARGT_SINT) {
1125 msg = "integer expected";
1126 goto error;
1127 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +02001128 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001129 break;
1130
1131 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001132 if (argp[idx].type != ARGT_STR) {
1133 msg = "string expected";
1134 goto error;
1135 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001136 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001137 if (!argp[idx].data.prx) {
1138 msg = "frontend doesn't exist";
1139 goto error;
1140 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001141 argp[idx].type = ARGT_FE;
1142 break;
1143
1144 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001145 if (argp[idx].type != ARGT_STR) {
1146 msg = "string expected";
1147 goto error;
1148 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001149 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001150 if (!argp[idx].data.prx) {
1151 msg = "backend doesn't exist";
1152 goto error;
1153 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001154 argp[idx].type = ARGT_BE;
1155 break;
1156
1157 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001158 if (argp[idx].type != ARGT_STR) {
1159 msg = "string expected";
1160 goto error;
1161 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001162 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001163 if (!argp[idx].data.t) {
1164 msg = "table doesn't exist";
1165 goto error;
1166 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001167 argp[idx].type = ARGT_TAB;
1168 break;
1169
1170 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001171 if (argp[idx].type != ARGT_STR) {
1172 msg = "string expected";
1173 goto error;
1174 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001175 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001176 if (sname) {
1177 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001178 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +02001179 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001180 if (!px) {
1181 msg = "backend doesn't exist";
1182 goto error;
1183 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001184 }
1185 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001186 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001187 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001188 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001189 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001190 if (!argp[idx].data.srv) {
1191 msg = "server doesn't exist";
1192 goto error;
1193 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001194 argp[idx].type = ARGT_SRV;
1195 break;
1196
1197 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001198 if (argp[idx].type != ARGT_STR) {
1199 msg = "string expected";
1200 goto error;
1201 }
1202 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
1203 msg = "invalid IPv4 address";
1204 goto error;
1205 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001206 argp[idx].type = ARGT_IPV4;
1207 break;
1208
1209 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +02001210 if (argp[idx].type == ARGT_SINT)
1211 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
1212 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001213 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
1214 msg = "invalid IPv4 mask";
1215 goto error;
1216 }
1217 }
1218 else {
1219 msg = "integer or string expected";
1220 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +02001221 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001222 argp[idx].type = ARGT_MSK4;
1223 break;
1224
1225 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001226 if (argp[idx].type != ARGT_STR) {
1227 msg = "string expected";
1228 goto error;
1229 }
1230 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
1231 msg = "invalid IPv6 address";
1232 goto error;
1233 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001234 argp[idx].type = ARGT_IPV6;
1235 break;
1236
1237 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +02001238 if (argp[idx].type == ARGT_SINT)
1239 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
1240 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001241 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
1242 msg = "invalid IPv6 mask";
1243 goto error;
1244 }
1245 }
1246 else {
1247 msg = "integer or string expected";
1248 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +02001249 }
Tim Duesterhusb814da62018-01-25 16:24:50 +01001250 argp[idx].type = ARGT_MSK6;
1251 break;
1252
Christopher Fauletfd2e9062020-08-06 11:10:57 +02001253 case ARGT_REG:
1254 if (argp[idx].type != ARGT_STR) {
1255 msg = "string expected";
1256 goto error;
1257 }
1258 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
1259 if (!reg) {
1260 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
1261 argp[idx].data.str.area, err);
1262 free(err);
1263 goto error;
1264 }
1265 argp[idx].type = ARGT_REG;
1266 argp[idx].data.reg = reg;
1267 break;
1268
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001269 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001270 if (argp[idx].type != ARGT_STR) {
1271 msg = "string expected";
1272 goto error;
1273 }
1274 if (p->uri_auth && p->uri_auth->userlist &&
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001275 strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area) == 0)
Christopher Fauletd25d9262020-08-06 11:04:46 +02001276 ul = p->uri_auth->userlist;
1277 else
1278 ul = auth_find_userlist(argp[idx].data.str.area);
1279
1280 if (!ul) {
1281 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
1282 goto error;
1283 }
1284 argp[idx].type = ARGT_USR;
1285 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001286 break;
1287
1288 case ARGT_STR:
1289 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
1290 msg = "unable to duplicate string arg";
1291 goto error;
1292 }
1293 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001294 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001295
Christopher Fauletd25d9262020-08-06 11:04:46 +02001296 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001297 msg = "type not yet supported";
1298 goto error;
1299 break;
1300
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001301 }
1302
1303 /* Check for type of argument. */
1304 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001305 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
1306 arg_type_names[(mask & ARGT_MASK)],
1307 arg_type_names[argp[idx].type & ARGT_MASK]);
1308 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001309 }
1310
1311 /* Next argument. */
1312 mask >>= ARGT_BITS;
1313 idx++;
1314 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001315 return 0;
1316
1317 error:
Olivier Houchardca431612022-09-13 00:31:17 +02001318 argp[idx].type = ARGT_STOP;
Willy Tarreauee0d7272021-07-16 10:26:56 +02001319 free_args(argp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001320 WILL_LJMP(luaL_argerror(L, first + idx, msg));
1321 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001322}
1323
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001324/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001325 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001326 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001327 *
1328 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001329 * - hlua_sethlua : create the association between hlua context and lua_state.
1330 */
Aurelien DARRAGON40cd44f2023-05-04 13:59:48 +02001331inline struct hlua *hlua_gethlua(lua_State *L)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001332{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001333 struct hlua **hlua = lua_getextraspace(L);
1334 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001335}
1336static inline void hlua_sethlua(struct hlua *hlua)
1337{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001338 struct hlua **hlua_store = lua_getextraspace(hlua->T);
1339 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001340}
1341
Willy Tarreau0b7b6392022-06-19 17:39:33 +02001342/* Will return a non-NULL string indicating the Lua call trace if the caller
1343 * currently is executing from within a Lua function. One line per entry will
1344 * be emitted, and each extra line will be prefixed with <pfx>. If a current
1345 * Lua function is not detected, NULL is returned.
1346 */
1347const char *hlua_show_current_location(const char *pfx)
1348{
1349 lua_State *L;
1350 lua_Debug ar;
1351
1352 /* global or per-thread stack initializing ? */
1353 if (hlua_state_id != -1 && (L = hlua_states[hlua_state_id]) && lua_getstack(L, 0, &ar))
1354 return hlua_traceback(L, pfx);
1355
1356 /* per-thread stack running ? */
1357 if (hlua_states[tid + 1] && (L = hlua_states[tid + 1]) && lua_getstack(L, 0, &ar))
1358 return hlua_traceback(L, pfx);
1359
1360 /* global stack running ? */
1361 if (hlua_states[0] && (L = hlua_states[0]) && lua_getstack(L, 0, &ar))
1362 return hlua_traceback(L, pfx);
1363
1364 return NULL;
1365}
1366
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001367/* This function is used to send logs. It try to send on screen (stderr)
1368 * and on the default syslog server.
1369 */
1370static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
1371{
1372 struct tm tm;
1373 char *p;
1374
1375 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001376 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001377 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001378 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +02001379 /* Break the message if exceed the buffer size. */
1380 *(p-4) = ' ';
1381 *(p-3) = '.';
1382 *(p-2) = '.';
1383 *(p-1) = '.';
1384 break;
1385 }
Willy Tarreau90807112020-02-25 08:16:33 +01001386 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001387 *p = *msg;
1388 else
1389 *p = '.';
1390 }
1391 *p = '\0';
1392
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001393 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001394 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +02001395 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
1396 return;
1397
Willy Tarreaua678b432015-08-28 10:14:59 +02001398 get_localtime(date.tv_sec, &tm);
1399 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001400 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001401 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001402 fflush(stderr);
1403 }
1404}
1405
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001406/* This function just ensure that the yield will be always
1407 * returned with a timeout and permit to set some flags
Aurelien DARRAGON2a9764b2023-04-04 18:41:04 +02001408 * <timeout> is a tick value
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001409 */
Aurelien DARRAGONbcdf07e2023-07-13 10:18:04 +02001410__LJMP void hlua_yieldk(lua_State *L, int nresults, lua_KContext ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001411 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001412{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001413 struct hlua *hlua;
1414
1415 /* Get hlua struct, or NULL if we execute from main lua state */
1416 hlua = hlua_gethlua(L);
1417 if (!hlua) {
1418 return;
1419 }
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001420
1421 /* Set the wake timeout. If timeout is required, we set
1422 * the expiration time.
1423 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001424 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001425
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +01001426 hlua->flags |= flags;
1427
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001428 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +02001429 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001430}
1431
Willy Tarreau87b09662015-04-03 00:22:06 +02001432/* This function initialises the Lua environment stored in the stream.
1433 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001434 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001435 *
1436 * This function is particular. it initialises a new Lua thread. If the
1437 * initialisation fails (example: out of memory error), the lua function
1438 * throws an error (longjmp).
1439 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001440 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001441 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001442 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001443 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001444 */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01001445int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001446{
1447 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001448 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001449 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001450 lua->wake_time = TICK_ETERNITY;
Thierry Fournier021d9862020-11-28 23:42:03 +01001451 lua->state_id = state_id;
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001452 hlua_timer_init(&lua->timer, 0); /* default value, no timeout */
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001453 LIST_INIT(&lua->com);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001454 MT_LIST_INIT(&lua->hc_list);
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01001455 if (!SET_SAFE_LJMP_PARENT(lua)) {
1456 lua->Tref = LUA_REFNIL;
1457 return 0;
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001458 }
Thierry Fournier021d9862020-11-28 23:42:03 +01001459 lua->T = lua_newthread(hlua_states[state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001460 if (!lua->T) {
1461 lua->Tref = LUA_REFNIL;
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01001462 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001463 return 0;
1464 }
1465 hlua_sethlua(lua);
Thierry Fournier021d9862020-11-28 23:42:03 +01001466 lua->Tref = luaL_ref(hlua_states[state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001467 lua->task = task;
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01001468 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001469 return 1;
1470}
1471
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001472/* kill all associated httpclient to this hlua task
1473 * We must take extra precautions as we're manipulating lua-exposed
1474 * objects without the main lua lock.
1475 */
William Lallemandbb581422022-10-20 10:57:28 +02001476static void hlua_httpclient_destroy_all(struct hlua *hlua)
1477{
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001478 struct hlua_httpclient *hlua_hc;
William Lallemandbb581422022-10-20 10:57:28 +02001479
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001480 /* use thread-safe accessors for hc_list since GC cycle initiated by
1481 * another thread sharing the same main lua stack (lua coroutine)
1482 * could execute hlua_httpclient_gc() on the hlua->hc_list items
1483 * in parallel: Lua GC applies on the main stack, it is not limited to
1484 * a single coroutine stack, see Github issue #2037 for reference.
1485 * Remember, coroutines created using lua_newthread() are not meant to
1486 * be thread safe in Lua. (From lua co-author:
1487 * http://lua-users.org/lists/lua-l/2011-07/msg00072.html)
1488 *
1489 * This security measure is superfluous when 'lua-load-per-thread' is used
1490 * since in this case coroutines exclusively run on the same thread
1491 * (main stack is not shared between OS threads).
1492 */
1493 while ((hlua_hc = MT_LIST_POP(&hlua->hc_list, typeof(hlua_hc), by_hlua))) {
1494 httpclient_stop_and_destroy(hlua_hc->hc);
William Lallemandbb581422022-10-20 10:57:28 +02001495 hlua_hc->hc = NULL;
William Lallemandbb581422022-10-20 10:57:28 +02001496 }
1497}
1498
1499
Willy Tarreau87b09662015-04-03 00:22:06 +02001500/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001501 * is destroyed. The destroy also the memory context. The struct "lua"
Aurelien DARRAGON60ab0f72023-03-01 16:45:50 +01001502 * will be freed.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001503 */
1504void hlua_ctx_destroy(struct hlua *lua)
1505{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001506 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001507 return;
1508
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001509 if (!lua->T)
1510 goto end;
1511
William Lallemandbb581422022-10-20 10:57:28 +02001512 /* clean all running httpclient */
1513 hlua_httpclient_destroy_all(lua);
1514
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001515 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001516 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001517
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001518 if (!SET_SAFE_LJMP(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001519 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001520 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001521 RESET_SAFE_LJMP(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001522
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001523 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001524 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001525 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001526 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001527 /* Forces a garbage collecting process. If the Lua program is finished
1528 * without error, we run the GC on the thread pointer. Its freed all
1529 * the unused memory.
1530 * If the thread is finnish with an error or is currently yielded,
1531 * it seems that the GC applied on the thread doesn't clean anything,
1532 * so e run the GC on the main thread.
1533 * NOTE: maybe this action locks all the Lua threads untiml the en of
1534 * the garbage collection.
1535 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001536 if (lua->gc_count) {
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001537 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001538 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001539 lua_gc(hlua_states[lua->state_id], LUA_GCCOLLECT, 0);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001540 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001541 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001542
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001543 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001544
1545end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001546 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001547}
1548
1549/* This function is used to restore the Lua context when a coroutine
1550 * fails. This function copy the common memory between old coroutine
1551 * and the new coroutine. The old coroutine is destroyed, and its
1552 * replaced by the new coroutine.
1553 * If the flag "keep_msg" is set, the last entry of the old is assumed
1554 * as string error message and it is copied in the new stack.
1555 */
1556static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1557{
1558 lua_State *T;
1559 int new_ref;
1560
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001561 /* New Lua coroutine. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001562 T = lua_newthread(hlua_states[lua->state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001563 if (!T)
1564 return 0;
1565
1566 /* Copy last error message. */
1567 if (keep_msg)
1568 lua_xmove(lua->T, T, 1);
1569
1570 /* Copy data between the coroutines. */
1571 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1572 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001573 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001574
1575 /* Destroy old data. */
1576 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1577
1578 /* The thread is garbage collected by Lua. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001579 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001580
1581 /* Fill the struct with the new coroutine values. */
1582 lua->Mref = new_ref;
1583 lua->T = T;
Thierry Fournier021d9862020-11-28 23:42:03 +01001584 lua->Tref = luaL_ref(hlua_states[lua->state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001585
1586 /* Set context. */
1587 hlua_sethlua(lua);
1588
1589 return 1;
1590}
1591
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001592void hlua_hook(lua_State *L, lua_Debug *ar)
1593{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001594 struct hlua *hlua;
1595
1596 /* Get hlua struct, or NULL if we execute from main lua state */
1597 hlua = hlua_gethlua(L);
1598 if (!hlua)
1599 return;
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001600
Aurelien DARRAGONcf0f7922023-04-07 16:34:20 +02001601 if (hlua->T != L) {
1602 /* We don't want to enforce a yield on a sub coroutine, since
1603 * we have no guarantees that the yield will be handled properly.
1604 * Indeed, only the hlua->T coroutine is being handled through
1605 * hlua_ctx_resume() function.
1606 *
1607 * Instead, we simply check for timeouts and wait for the sub
1608 * coroutine to finish..
1609 */
1610 goto check_timeout;
1611 }
1612
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001613 /* Lua cannot yield when its returning from a function,
1614 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001615 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001616 */
1617 if (lua_gethookmask(L) & LUA_MASKRET) {
1618 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1619 return;
1620 }
1621
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001622 /* If we interrupt the Lua processing in yieldable state, we yield.
1623 * If the state is not yieldable, trying yield causes an error.
1624 */
Aurelien DARRAGON0ebd41f2022-11-24 09:51:40 +01001625 if (lua_isyieldable(L)) {
1626 /* note: for converters/fetches.. where yielding is not allowed
1627 * hlua_ctx_resume() will simply perform a goto resume_execution
1628 * instead of rescheduling hlua->task.
1629 * also: hlua_ctx_resume() will take care of checking execution
1630 * timeout and re-applying the hook as needed.
1631 */
Willy Tarreau9635e032018-10-16 17:52:55 +02001632 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Aurelien DARRAGON0ebd41f2022-11-24 09:51:40 +01001633 /* lua docs says that the hook should return immediately after lua_yieldk
1634 *
1635 * From: https://www.lua.org/manual/5.3/manual.html#lua_yieldk
1636 *
1637 * Moreover, it seems that we don't want to continue after the yield
1638 * because the end of the function is about handling unyieldable function,
1639 * which is not the case here.
1640 *
1641 * ->if we don't return lua_sethook gets incorrectly set with MASKRET later
1642 * in the function.
1643 */
1644 return;
1645 }
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001646
Aurelien DARRAGONcf0f7922023-04-07 16:34:20 +02001647 check_timeout:
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001648 /* If we cannot yield, check the timeout. */
1649 if (!hlua_timer_check(&hlua->timer)) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001650 lua_pushfstring(L, "execution timeout");
1651 WILL_LJMP(lua_error(L));
1652 }
1653
1654 /* Try to interrupt the process at the end of the current
1655 * unyieldable function.
1656 */
1657 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001658}
1659
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001660/* This function start or resumes the Lua stack execution. If the flag
1661 * "yield_allowed" if no set and the LUA stack execution returns a yield
1662 * The function return an error.
1663 *
1664 * The function can returns 4 values:
1665 * - HLUA_E_OK : The execution is terminated without any errors.
1666 * - HLUA_E_AGAIN : The execution must continue at the next associated
1667 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001668 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001669 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001670 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001671 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001672 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001673 * LUA code.
1674 */
1675static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1676{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001677#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1678 int nres;
1679#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001680 int ret;
1681 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001682 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001683
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001684 /* Lock the whole Lua execution. This lock must be before the
1685 * label "resume_execution".
1686 */
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +01001687 hlua_lock(lua);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001688
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001689 /* reset the timer as we might be re-entering the function to
1690 * resume the coroutine after a successful yield
1691 * (cumulative time will be updated)
1692 */
1693 hlua_timer_reset(&lua->timer);
1694
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001695resume_execution:
1696
1697 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1698 * instructions. it is used for preventing infinite loops.
1699 */
1700 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1701
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001702 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001703 HLUA_SET_RUN(lua);
1704 HLUA_CLR_CTRLYIELD(lua);
1705 HLUA_CLR_WAKERESWR(lua);
1706 HLUA_CLR_WAKEREQWR(lua);
Christopher Faulet1f43a342021-08-04 17:58:21 +02001707 HLUA_CLR_NOYIELD(lua);
1708 if (!yield_allowed)
1709 HLUA_SET_NOYIELD(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001710
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001711 /* reset wake_time. */
Christopher Fauletbc275a92020-02-26 14:55:16 +01001712 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001713
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001714 /* start the timer as we're about to start lua processing */
1715 hlua_timer_start(&lua->timer);
1716
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001717 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001718#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournier021d9862020-11-28 23:42:03 +01001719 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs, &nres);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001720#else
Thierry Fournier021d9862020-11-28 23:42:03 +01001721 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001722#endif
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001723
1724 /* out of lua processing, stop the timer */
1725 hlua_timer_stop(&lua->timer);
1726
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001727 switch (ret) {
1728
1729 case LUA_OK:
1730 ret = HLUA_E_OK;
1731 break;
1732
1733 case LUA_YIELD:
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001734 /* Check if the execution timeout is expired. If it is the case, we
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001735 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001736 */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01001737 if (!hlua_timer_check(&lua->timer)) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001738 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001739 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001740 break;
1741 }
1742 /* Process the forced yield. if the general yield is not allowed or
1743 * if no task were associated this the current Lua execution
1744 * coroutine, we resume the execution. Else we want to return in the
1745 * scheduler and we want to be waked up again, to continue the
1746 * current Lua execution. So we schedule our own task.
1747 */
1748 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001749 if (!yield_allowed || !lua->task)
1750 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001751 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001752 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001753 if (!yield_allowed) {
1754 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001755 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001756 break;
1757 }
1758 ret = HLUA_E_AGAIN;
1759 break;
1760
1761 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001762
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001763 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001764 * because the errors ares the only one mean to return immediately
1765 * from and lua execution.
1766 */
1767 if (lua->flags & HLUA_EXIT) {
1768 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001769 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001770 break;
1771 }
1772
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001773 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001774 if (!lua_checkstack(lua->T, 1)) {
1775 ret = HLUA_E_ERR;
1776 break;
1777 }
1778 msg = lua_tostring(lua->T, -1);
1779 lua_settop(lua->T, 0); /* Empty the stack. */
Christopher Fauletd09cc512021-03-24 14:48:45 +01001780 trace = hlua_traceback(lua->T, ", ");
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001781 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001782 lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001783 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001784 lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001785 ret = HLUA_E_ERRMSG;
1786 break;
1787
1788 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001789 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001790 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001791 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001792 break;
1793
1794 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001795 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001796 if (!lua_checkstack(lua->T, 1)) {
1797 ret = HLUA_E_ERR;
1798 break;
1799 }
1800 msg = lua_tostring(lua->T, -1);
1801 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001802 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001803 lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001804 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001805 lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001806 ret = HLUA_E_ERRMSG;
1807 break;
1808
1809 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001810 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001811 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001812 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001813 break;
1814 }
1815
1816 switch (ret) {
1817 case HLUA_E_AGAIN:
1818 break;
1819
1820 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001821 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001822 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001823 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001824 break;
1825
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001826 case HLUA_E_ETMOUT:
1827 case HLUA_E_NOMEM:
1828 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001829 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001830 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001831 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001832 hlua_ctx_renew(lua, 0);
1833 break;
1834
1835 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001836 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001837 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001838 break;
1839 }
1840
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001841 /* This is the main exit point, remove the Lua lock. */
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +01001842 hlua_unlock(lua);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001843
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001844 return ret;
1845}
1846
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001847/* This function exit the current code. */
1848__LJMP static int hlua_done(lua_State *L)
1849{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001850 struct hlua *hlua;
1851
1852 /* Get hlua struct, or NULL if we execute from main lua state */
1853 hlua = hlua_gethlua(L);
1854 if (!hlua)
1855 return 0;
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001856
1857 hlua->flags |= HLUA_EXIT;
1858 WILL_LJMP(lua_error(L));
1859
1860 return 0;
1861}
1862
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001863/* This function is an LUA binding. It provides a function
1864 * for deleting ACL from a referenced ACL file.
1865 */
1866__LJMP static int hlua_del_acl(lua_State *L)
1867{
1868 const char *name;
1869 const char *key;
1870 struct pat_ref *ref;
1871
1872 MAY_LJMP(check_args(L, 2, "del_acl"));
1873
1874 name = MAY_LJMP(luaL_checkstring(L, 1));
1875 key = MAY_LJMP(luaL_checkstring(L, 2));
1876
1877 ref = pat_ref_lookup(name);
1878 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001879 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001880
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001881 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001882 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001883 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001884 return 0;
1885}
1886
1887/* This function is an LUA binding. It provides a function
1888 * for deleting map entry from a referenced map file.
1889 */
1890static int hlua_del_map(lua_State *L)
1891{
1892 const char *name;
1893 const char *key;
1894 struct pat_ref *ref;
1895
1896 MAY_LJMP(check_args(L, 2, "del_map"));
1897
1898 name = MAY_LJMP(luaL_checkstring(L, 1));
1899 key = MAY_LJMP(luaL_checkstring(L, 2));
1900
1901 ref = pat_ref_lookup(name);
1902 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001903 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001904
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001905 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001906 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001907 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001908 return 0;
1909}
1910
1911/* This function is an LUA binding. It provides a function
1912 * for adding ACL pattern from a referenced ACL file.
1913 */
1914static int hlua_add_acl(lua_State *L)
1915{
1916 const char *name;
1917 const char *key;
1918 struct pat_ref *ref;
1919
1920 MAY_LJMP(check_args(L, 2, "add_acl"));
1921
1922 name = MAY_LJMP(luaL_checkstring(L, 1));
1923 key = MAY_LJMP(luaL_checkstring(L, 2));
1924
1925 ref = pat_ref_lookup(name);
1926 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001927 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001928
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001929 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001930 if (pat_ref_find_elt(ref, key) == NULL)
1931 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001932 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001933 return 0;
1934}
1935
1936/* This function is an LUA binding. It provides a function
1937 * for setting map pattern and sample from a referenced map
1938 * file.
1939 */
1940static int hlua_set_map(lua_State *L)
1941{
1942 const char *name;
1943 const char *key;
1944 const char *value;
1945 struct pat_ref *ref;
1946
1947 MAY_LJMP(check_args(L, 3, "set_map"));
1948
1949 name = MAY_LJMP(luaL_checkstring(L, 1));
1950 key = MAY_LJMP(luaL_checkstring(L, 2));
1951 value = MAY_LJMP(luaL_checkstring(L, 3));
1952
1953 ref = pat_ref_lookup(name);
1954 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001955 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001956
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001957 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001958 if (pat_ref_find_elt(ref, key) != NULL)
1959 pat_ref_set(ref, key, value, NULL);
1960 else
1961 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001962 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001963 return 0;
1964}
1965
Aurelien DARRAGON5bed48f2023-04-21 17:32:46 +02001966/* This function disables the sending of email through the
1967 * legacy email sending function which is implemented using
1968 * checks.
1969 *
1970 * It may not be used during runtime.
1971 */
1972__LJMP static int hlua_disable_legacy_mailers(lua_State *L)
1973{
1974 if (hlua_gethlua(L))
1975 WILL_LJMP(luaL_error(L, "disable_legacy_mailers: "
1976 "not available outside of init or body context"));
1977 send_email_disabled = 1;
1978 return 0;
1979}
1980
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001981/* A class is a lot of memory that contain data. This data can be a table,
1982 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001983 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001984 * the name of the object (_G[<name>] = <metable> ).
1985 *
1986 * A metable is a table that modify the standard behavior of a standard
1987 * access to the associated data. The entries of this new metatable are
1988 * defined as is:
1989 *
1990 * http://lua-users.org/wiki/MetatableEvents
1991 *
1992 * __index
1993 *
1994 * we access an absent field in a table, the result is nil. This is
1995 * true, but it is not the whole truth. Actually, such access triggers
1996 * the interpreter to look for an __index metamethod: If there is no
1997 * such method, as usually happens, then the access results in nil;
1998 * otherwise, the metamethod will provide the result.
1999 *
2000 * Control 'prototype' inheritance. When accessing "myTable[key]" and
2001 * the key does not appear in the table, but the metatable has an __index
2002 * property:
2003 *
2004 * - if the value is a function, the function is called, passing in the
2005 * table and the key; the return value of that function is returned as
2006 * the result.
2007 *
2008 * - if the value is another table, the value of the key in that table is
2009 * asked for and returned (and if it doesn't exist in that table, but that
2010 * table's metatable has an __index property, then it continues on up)
2011 *
2012 * - Use "rawget(myTable,key)" to skip this metamethod.
2013 *
2014 * http://www.lua.org/pil/13.4.1.html
2015 *
2016 * __newindex
2017 *
2018 * Like __index, but control property assignment.
2019 *
2020 * __mode - Control weak references. A string value with one or both
2021 * of the characters 'k' and 'v' which specifies that the the
2022 * keys and/or values in the table are weak references.
2023 *
2024 * __call - Treat a table like a function. When a table is followed by
2025 * parenthesis such as "myTable( 'foo' )" and the metatable has
2026 * a __call key pointing to a function, that function is invoked
2027 * (passing any specified arguments) and the return value is
2028 * returned.
2029 *
2030 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
2031 * called, if the metatable for myTable has a __metatable
2032 * key, the value of that key is returned instead of the
2033 * actual metatable.
2034 *
2035 * __tostring - Control string representation. When the builtin
2036 * "tostring( myTable )" function is called, if the metatable
2037 * for myTable has a __tostring property set to a function,
2038 * that function is invoked (passing myTable to it) and the
2039 * return value is used as the string representation.
2040 *
2041 * __len - Control table length. When the table length is requested using
2042 * the length operator ( '#' ), if the metatable for myTable has
2043 * a __len key pointing to a function, that function is invoked
2044 * (passing myTable to it) and the return value used as the value
2045 * of "#myTable".
2046 *
2047 * __gc - Userdata finalizer code. When userdata is set to be garbage
2048 * collected, if the metatable has a __gc field pointing to a
2049 * function, that function is first invoked, passing the userdata
2050 * to it. The __gc metamethod is not called for tables.
2051 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
2052 *
2053 * Special metamethods for redefining standard operators:
2054 * http://www.lua.org/pil/13.1.html
2055 *
2056 * __add "+"
2057 * __sub "-"
2058 * __mul "*"
2059 * __div "/"
2060 * __unm "!"
2061 * __pow "^"
2062 * __concat ".."
2063 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002064 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01002065 * http://www.lua.org/pil/13.2.html
2066 *
2067 * __eq "=="
2068 * __lt "<"
2069 * __le "<="
2070 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002071
2072/*
2073 *
2074 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002075 * Class Map
2076 *
2077 *
2078 */
2079
2080/* Returns a struct hlua_map if the stack entry "ud" is
2081 * a class session, otherwise it throws an error.
2082 */
2083__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
2084{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002085 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002086}
2087
2088/* This function is the map constructor. It don't need
2089 * the class Map object. It creates and return a new Map
2090 * object. It must be called only during "body" or "init"
2091 * context because it process some filesystem accesses.
2092 */
2093__LJMP static int hlua_map_new(struct lua_State *L)
2094{
2095 const char *fn;
2096 int match = PAT_MATCH_STR;
2097 struct sample_conv conv;
2098 const char *file = "";
2099 int line = 0;
2100 lua_Debug ar;
2101 char *err = NULL;
2102 struct arg args[2];
2103
2104 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
2105 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
2106
2107 fn = MAY_LJMP(luaL_checkstring(L, 1));
2108
2109 if (lua_gettop(L) >= 2) {
2110 match = MAY_LJMP(luaL_checkinteger(L, 2));
2111 if (match < 0 || match >= PAT_MATCH_NUM)
2112 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
2113 }
2114
2115 /* Get Lua filename and line number. */
2116 if (lua_getstack(L, 1, &ar)) { /* check function at level */
2117 lua_getinfo(L, "Sl", &ar); /* get info about it */
2118 if (ar.currentline > 0) { /* is there info? */
2119 file = ar.short_src;
2120 line = ar.currentline;
2121 }
2122 }
2123
2124 /* fill fake sample_conv struct. */
2125 conv.kw = ""; /* unused. */
2126 conv.process = NULL; /* unused. */
2127 conv.arg_mask = 0; /* unused. */
2128 conv.val_args = NULL; /* unused. */
2129 conv.out_type = SMP_T_STR;
2130 conv.private = (void *)(long)match;
2131 switch (match) {
2132 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
2133 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
2134 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
2135 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
2136 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
2137 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
2138 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02002139 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002140 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
2141 default:
2142 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
2143 }
2144
2145 /* fill fake args. */
2146 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02002147 args[0].data.str.area = strdup(fn);
2148 args[0].data.str.data = strlen(fn);
2149 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002150 args[1].type = ARGT_STOP;
2151
2152 /* load the map. */
2153 if (!sample_load_map(args, &conv, file, line, &err)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002154 /* error case: we can't use luaL_error because we must
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002155 * free the err variable.
2156 */
2157 luaL_where(L, 1);
2158 lua_pushfstring(L, "'new': %s.", err);
2159 lua_concat(L, 2);
2160 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02002161 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002162 WILL_LJMP(lua_error(L));
2163 }
2164
2165 /* create the lua object. */
2166 lua_newtable(L);
2167 lua_pushlightuserdata(L, args[0].data.map);
2168 lua_rawseti(L, -2, 0);
2169
2170 /* Pop a class Map metatable and affect it to the userdata. */
2171 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
2172 lua_setmetatable(L, -2);
2173
2174
2175 return 1;
2176}
2177
2178__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
2179{
2180 struct map_descriptor *desc;
2181 struct pattern *pat;
2182 struct sample smp;
2183
2184 MAY_LJMP(check_args(L, 2, "lookup"));
2185 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02002186 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002187 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002188 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002189 }
2190 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002191 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002192 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002193 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 +01002194 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002195 }
2196
2197 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02002198 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002199 if (str)
2200 lua_pushstring(L, "");
2201 else
2202 lua_pushnil(L);
2203 return 1;
2204 }
2205
2206 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002207 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002208 return 1;
2209}
2210
2211__LJMP static int hlua_map_lookup(struct lua_State *L)
2212{
2213 return _hlua_map_lookup(L, 0);
2214}
2215
2216__LJMP static int hlua_map_slookup(struct lua_State *L)
2217{
2218 return _hlua_map_lookup(L, 1);
2219}
2220
2221/*
2222 *
2223 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002224 * Class Socket
2225 *
2226 *
2227 */
2228
2229__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
2230{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002231 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002232}
2233
2234/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002235 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002236 * received.
2237 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002238static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002239{
Willy Tarreau5321da92022-05-06 11:57:34 +02002240 struct hlua_csk_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002241 struct stconn *sc = appctx_sc(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002242
Christopher Faulet31572222023-03-31 11:13:48 +02002243 if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW)))) {
Aurelien DARRAGONa2c53212023-05-02 19:10:24 +02002244 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
Christopher Faulet31572222023-03-31 11:13:48 +02002245 notification_wake(&ctx->wake_on_read);
2246 notification_wake(&ctx->wake_on_write);
2247 return;
2248 }
2249
Willy Tarreau5321da92022-05-06 11:57:34 +02002250 if (ctx->die) {
Christopher Faulet31572222023-03-31 11:13:48 +02002251 se_fl_set(appctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Willy Tarreau5321da92022-05-06 11:57:34 +02002252 notification_wake(&ctx->wake_on_read);
2253 notification_wake(&ctx->wake_on_write);
Christopher Faulet31572222023-03-31 11:13:48 +02002254 return;
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002255 }
2256
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002257 /* If we can't write, wakeup the pending write signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002258 if (channel_output_closed(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002259 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002260
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002261 /* If we can't read, wakeup the pending read signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002262 if (channel_input_closed(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002263 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002264
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002265 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002266 * to be notified whenever the connection completes.
2267 */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002268 if (sc_opposite(sc)->state < SC_ST_EST) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02002269 applet_need_more_data(appctx);
Willy Tarreaub23edc82022-05-24 16:49:03 +02002270 se_need_remote_conn(appctx->sedesc);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002271 applet_have_more_data(appctx);
Willy Tarreaud4da1962015-04-20 01:31:23 +02002272 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002273 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002274
2275 /* This function is called after the connect. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002276 ctx->connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002277
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002278 /* Wake the tasks which wants to write if the buffer have available space. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002279 if (channel_may_recv(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002280 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002281
2282 /* Wake the tasks which wants to read if the buffer contains data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002283 if (!channel_is_empty(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002284 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002285
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002286 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01002287 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002288 */
Willy Tarreau5321da92022-05-06 11:57:34 +02002289 if (notification_registered(&ctx->wake_on_write))
Willy Tarreau4164eb92022-05-25 15:42:03 +02002290 applet_have_more_data(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002291}
2292
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002293static int hlua_socket_init(struct appctx *appctx)
2294{
2295 struct hlua_csk_ctx *ctx = appctx->svcctx;
2296 struct stream *s;
2297
2298 if (appctx_finalize_startup(appctx, socket_proxy, &BUF_NULL) == -1)
2299 goto error;
2300
2301 s = appctx_strm(appctx);
2302
Willy Tarreau4596fe22022-05-17 19:07:51 +02002303 /* Configure "right" stream connector. This stconn is used to connect
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002304 * and retrieve data from the server. The connection is initialized
2305 * with the "struct server".
2306 */
Willy Tarreau74568cf2022-05-27 09:03:30 +02002307 sc_set_state(s->scb, SC_ST_ASS);
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002308
2309 /* Force destination server. */
2310 s->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
2311 s->target = &socket_tcp->obj_type;
2312
2313 ctx->appctx = appctx;
2314 return 0;
2315
2316 error:
2317 return -1;
2318}
2319
Willy Tarreau87b09662015-04-03 00:22:06 +02002320/* This function is called when the "struct stream" is destroyed.
2321 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002322 * Wake all the pending signals.
2323 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002324static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002325{
Willy Tarreau5321da92022-05-06 11:57:34 +02002326 struct hlua_csk_ctx *ctx = appctx->svcctx;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002327 struct xref *peer;
2328
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002329 /* Remove my link in the original objects. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002330 peer = xref_get_peer_and_lock(&ctx->xref);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002331 if (peer)
Willy Tarreau5321da92022-05-06 11:57:34 +02002332 xref_disconnect(&ctx->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002333
2334 /* Wake all the task waiting for me. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002335 notification_wake(&ctx->wake_on_read);
2336 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002337}
2338
2339/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02002340 * uses this object. If the stream does not exists, just quit.
2341 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002342 * pending signal can rest in the read and write lists. destroy
2343 * it.
2344 */
2345__LJMP static int hlua_socket_gc(lua_State *L)
2346{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002347 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002348 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002349 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002350
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002351 MAY_LJMP(check_args(L, 1, "__gc"));
2352
2353 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002354 peer = xref_get_peer_and_lock(&socket->xref);
2355 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002356 return 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02002357
2358 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002359
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002360 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002361 ctx->die = 1;
2362 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002363
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002364 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002365 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002366 return 0;
2367}
2368
2369/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02002370 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002371 */
sada05ed3302018-05-11 11:48:18 -07002372__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002373{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002374 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002375 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002376 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002377 struct hlua *hlua;
2378
2379 /* Get hlua struct, or NULL if we execute from main lua state */
2380 hlua = hlua_gethlua(L);
2381 if (!hlua)
2382 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002383
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002384 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002385
2386 /* Check if we run on the same thread than the xreator thread.
2387 * We cannot access to the socket if the thread is different.
2388 */
2389 if (socket->tid != tid)
2390 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2391
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002392 peer = xref_get_peer_and_lock(&socket->xref);
2393 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002394 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01002395
2396 hlua->gc_count--;
Willy Tarreau5321da92022-05-06 11:57:34 +02002397 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002398
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002399 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002400 ctx->die = 1;
2401 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002402
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002403 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002404 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002405 return 0;
2406}
2407
sada05ed3302018-05-11 11:48:18 -07002408/* The close function calls close_helper.
2409 */
2410__LJMP static int hlua_socket_close(lua_State *L)
2411{
2412 MAY_LJMP(check_args(L, 1, "close"));
2413 return hlua_socket_close_helper(L);
2414}
2415
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002416/* This Lua function assumes that the stack contain three parameters.
2417 * 1 - USERDATA containing a struct socket
2418 * 2 - INTEGER with values of the macro defined below
2419 * If the integer is -1, we must read at most one line.
2420 * If the integer is -2, we ust read all the data until the
2421 * end of the stream.
2422 * If the integer is positive value, we must read a number of
2423 * bytes corresponding to this value.
2424 */
2425#define HLSR_READ_LINE (-1)
2426#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002427__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002428{
2429 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
2430 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002431 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002432 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002433 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002434 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002435 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02002436 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002437 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02002438 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002439 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002440 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01002441 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002442 struct stream *s;
2443 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002444 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002445
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002446 /* Get hlua struct, or NULL if we execute from main lua state */
2447 hlua = hlua_gethlua(L);
2448
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002449 /* Check if this lua stack is schedulable. */
2450 if (!hlua || !hlua->task)
2451 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
2452 "'frontend', 'backend' or 'task'"));
2453
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);
2462 if (!peer)
2463 goto no_peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002464
2465 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2466 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002467 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002468
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002469 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002470 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002471 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002472 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002473 if (nblk < 0) /* Connection close. */
2474 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002475 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002476 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002477
2478 /* remove final \r\n. */
2479 if (nblk == 1) {
2480 if (blk1[len1-1] == '\n') {
2481 len1--;
2482 skip_at_end++;
2483 if (blk1[len1-1] == '\r') {
2484 len1--;
2485 skip_at_end++;
2486 }
2487 }
2488 }
2489 else {
2490 if (blk2[len2-1] == '\n') {
2491 len2--;
2492 skip_at_end++;
2493 if (blk2[len2-1] == '\r') {
2494 len2--;
2495 skip_at_end++;
2496 }
2497 }
2498 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002499 }
2500
2501 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002502 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002503 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002504 if (nblk < 0) /* Connection close. */
2505 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002506 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002507 goto connection_empty;
2508 }
2509
2510 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002511 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002512 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002513 if (nblk < 0) /* Connection close. */
2514 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002515 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002516 goto connection_empty;
2517
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002518 missing_bytes = wanted - socket->b.n;
2519 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002520 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002521 len1 = missing_bytes;
2522 } if (nblk == 2 && len1 + len2 > missing_bytes)
2523 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002524 }
2525
2526 len = len1;
2527
2528 luaL_addlstring(&socket->b, blk1, len1);
2529 if (nblk == 2) {
2530 len += len2;
2531 luaL_addlstring(&socket->b, blk2, len2);
2532 }
2533
2534 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002535 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002536
2537 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002538 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002539
2540 /* If the pattern reclaim to read all the data
2541 * in the connection, got out.
2542 */
2543 if (wanted == HLSR_READ_ALL)
2544 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002545 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002546 goto connection_empty;
2547
2548 /* Return result. */
2549 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002550 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002551 return 1;
2552
2553connection_closed:
2554
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002555 xref_unlock(&socket->xref, peer);
2556
2557no_peer:
2558
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002559 /* If the buffer containds data. */
2560 if (socket->b.n > 0) {
2561 luaL_pushresult(&socket->b);
2562 return 1;
2563 }
2564 lua_pushnil(L);
2565 lua_pushstring(L, "connection closed.");
2566 return 2;
2567
2568connection_empty:
2569
Willy Tarreau5321da92022-05-06 11:57:34 +02002570 if (!notification_new(&hlua->com, &csk_ctx->wake_on_read, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002571 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002572 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002573 }
2574 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002575 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002576 return 0;
2577}
2578
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002579/* This Lua function gets two parameters. The first one can be string
2580 * or a number. If the string is "*l", the user requires one line. If
2581 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002582 * If the value is a number, the user require a number of bytes equal
2583 * to the value. The default value is "*l" (a line).
2584 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002585 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002586 * integer takes this values:
2587 * -1 : read a line
2588 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002589 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002590 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002591 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002592 * concatenated with the read data.
2593 */
2594__LJMP static int hlua_socket_receive(struct lua_State *L)
2595{
2596 int wanted = HLSR_READ_LINE;
2597 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002598 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002599 char *error;
2600 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002601 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002602
2603 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2604 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2605
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002606 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002607
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002608 /* Check if we run on the same thread than the xreator thread.
2609 * We cannot access to the socket if the thread is different.
2610 */
2611 if (socket->tid != tid)
2612 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2613
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002614 /* check for pattern. */
2615 if (lua_gettop(L) >= 2) {
2616 type = lua_type(L, 2);
2617 if (type == LUA_TSTRING) {
2618 pattern = lua_tostring(L, 2);
2619 if (strcmp(pattern, "*a") == 0)
2620 wanted = HLSR_READ_ALL;
2621 else if (strcmp(pattern, "*l") == 0)
2622 wanted = HLSR_READ_LINE;
2623 else {
2624 wanted = strtoll(pattern, &error, 10);
2625 if (*error != '\0')
2626 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2627 }
2628 }
2629 else if (type == LUA_TNUMBER) {
2630 wanted = lua_tointeger(L, 2);
2631 if (wanted < 0)
2632 WILL_LJMP(luaL_error(L, "Unsupported size."));
2633 }
2634 }
2635
2636 /* Set pattern. */
2637 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002638
2639 /* Check if we would replace the top by itself. */
2640 if (lua_gettop(L) != 2)
2641 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002642
Christopher Fauletc31b2002021-05-03 10:11:13 +02002643 /* Save index of the top of the stack because since buffers are used, it
2644 * may change
2645 */
2646 lastarg = lua_gettop(L);
2647
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002648 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002649 luaL_buffinit(L, &socket->b);
2650
2651 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002652 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002653 if (lua_type(L, 3) != LUA_TSTRING)
2654 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2655 pattern = lua_tolstring(L, 3, &len);
2656 luaL_addlstring(&socket->b, pattern, len);
2657 }
2658
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002659 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002660}
2661
2662/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002663 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002664 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002665static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002666{
2667 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002668 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002669 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002670 struct appctx *appctx;
2671 size_t buf_len;
2672 const char *buf;
2673 int len;
2674 int send_len;
2675 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002676 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002677 struct stream *s;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002678 struct stconn *sc;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002679
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002680 /* Get hlua struct, or NULL if we execute from main lua state */
2681 hlua = hlua_gethlua(L);
2682
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002683 /* Check if this lua stack is schedulable. */
2684 if (!hlua || !hlua->task)
2685 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2686 "'frontend', 'backend' or 'task'"));
2687
2688 /* Get object */
2689 socket = MAY_LJMP(hlua_checksocket(L, 1));
2690 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002691 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002692
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002693 /* Check if we run on the same thread than the xreator thread.
2694 * We cannot access to the socket if the thread is different.
2695 */
2696 if (socket->tid != tid)
2697 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2698
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002699 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002700 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002701 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002702 lua_pushinteger(L, -1);
2703 return 1;
2704 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002705
2706 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2707 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002708 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002709 s = __sc_strm(sc);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002710
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002711 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002712 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002713 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002714 lua_pushinteger(L, -1);
2715 return 1;
2716 }
2717
2718 /* Update the input buffer data. */
2719 buf += sent;
2720 send_len = buf_len - sent;
2721
2722 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002723 if (sent >= buf_len) {
2724 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002725 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002726 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002727
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002728 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002729 * the request buffer if its not required.
2730 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002731 if (s->req.buf.size == 0) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02002732 if (!sc_alloc_ibuf(sc, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002733 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002734 }
2735
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002736 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002737 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002738 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002739 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002740 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002741
2742 /* send data */
2743 if (len < send_len)
2744 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002745 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002746
2747 /* "Not enough space" (-1), "Buffer too little to contain
2748 * the data" (-2) are not expected because the available length
2749 * is tested.
2750 * Other unknown error are also not expected.
2751 */
2752 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002753 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002754 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002755
sada05ed3302018-05-11 11:48:18 -07002756 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002757 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002758 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002759 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002760 return 1;
2761 }
2762
2763 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002764 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002765
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002766 /* Update length sent. */
2767 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002768 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002769
2770 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002771 if (sent + len >= buf_len) {
2772 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002773 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002774 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002775
2776hlua_socket_write_yield_return:
Willy Tarreau5321da92022-05-06 11:57:34 +02002777 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002778 xref_unlock(&socket->xref, peer);
2779 WILL_LJMP(luaL_error(L, "out of memory"));
2780 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002781 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002782 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002783 return 0;
2784}
2785
2786/* This function initiate the send of data. It just check the input
2787 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002788 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002789 * "hlua_socket_write_yield" that can yield.
2790 *
2791 * The Lua function gets between 3 and 4 parameters. The first one is
2792 * the associated object. The second is a string buffer. The third is
2793 * a facultative integer that represents where is the buffer position
2794 * of the start of the data that can send. The first byte is the
2795 * position "1". The default value is "1". The fourth argument is a
2796 * facultative integer that represents where is the buffer position
2797 * of the end of the data that can send. The default is the last byte.
2798 */
2799static int hlua_socket_send(struct lua_State *L)
2800{
2801 int i;
2802 int j;
2803 const char *buf;
2804 size_t buf_len;
2805
2806 /* Check number of arguments. */
2807 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2808 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2809
2810 /* Get the string. */
2811 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2812
2813 /* Get and check j. */
2814 if (lua_gettop(L) == 4) {
2815 j = MAY_LJMP(luaL_checkinteger(L, 4));
2816 if (j < 0)
2817 j = buf_len + j + 1;
2818 if (j > buf_len)
2819 j = buf_len + 1;
2820 lua_pop(L, 1);
2821 }
2822 else
2823 j = buf_len;
2824
2825 /* Get and check i. */
2826 if (lua_gettop(L) == 3) {
2827 i = MAY_LJMP(luaL_checkinteger(L, 3));
2828 if (i < 0)
2829 i = buf_len + i + 1;
2830 if (i > buf_len)
2831 i = buf_len + 1;
2832 lua_pop(L, 1);
2833 } else
2834 i = 1;
2835
2836 /* Check bth i and j. */
2837 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002838 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002839 return 1;
2840 }
2841 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002842 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002843 return 1;
2844 }
2845 if (i == 0)
2846 i = 1;
2847 if (j == 0)
2848 j = 1;
2849
2850 /* Pop the string. */
2851 lua_pop(L, 1);
2852
2853 /* Update the buffer length. */
2854 buf += i - 1;
2855 buf_len = j - i + 1;
2856 lua_pushlstring(L, buf, buf_len);
2857
2858 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002859 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002860
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002861 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002862}
2863
Willy Tarreau22b0a682015-06-17 19:43:49 +02002864#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Christopher Faulete6465b32021-10-22 15:36:08 +02002865__LJMP static inline int hlua_socket_info(struct lua_State *L, const struct sockaddr_storage *addr)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002866{
2867 static char buffer[SOCKET_INFO_MAX_LEN];
2868 int ret;
2869 int len;
2870 char *p;
2871
2872 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2873 if (ret <= 0) {
2874 lua_pushnil(L);
2875 return 1;
2876 }
2877
2878 if (ret == AF_UNIX) {
2879 lua_pushstring(L, buffer+1);
2880 return 1;
2881 }
2882 else if (ret == AF_INET6) {
2883 buffer[0] = '[';
2884 len = strlen(buffer);
2885 buffer[len] = ']';
2886 len++;
2887 buffer[len] = ':';
2888 len++;
2889 p = buffer;
2890 }
2891 else if (ret == AF_INET) {
2892 p = buffer + 1;
2893 len = strlen(p);
2894 p[len] = ':';
2895 len++;
2896 }
2897 else {
2898 lua_pushnil(L);
2899 return 1;
2900 }
2901
2902 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2903 lua_pushnil(L);
2904 return 1;
2905 }
2906
2907 lua_pushstring(L, p);
2908 return 1;
2909}
2910
2911/* Returns information about the peer of the connection. */
2912__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2913{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002914 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002915 struct xref *peer;
2916 struct appctx *appctx;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002917 struct stconn *sc;
Christopher Faulet16f16af2021-10-27 09:34:56 +02002918 const struct sockaddr_storage *dst;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002919 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002920
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002921 MAY_LJMP(check_args(L, 1, "getpeername"));
2922
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002923 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002924
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002925 /* Check if we run on the same thread than the xreator thread.
2926 * We cannot access to the socket if the thread is different.
2927 */
2928 if (socket->tid != tid)
2929 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2930
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002931 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002932 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002933 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002934 lua_pushnil(L);
2935 return 1;
2936 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002937
2938 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002939 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002940 dst = sc_dst(sc_opposite(sc));
Christopher Faulet16f16af2021-10-27 09:34:56 +02002941 if (!dst) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002942 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002943 lua_pushnil(L);
2944 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002945 }
2946
Christopher Faulet16f16af2021-10-27 09:34:56 +02002947 ret = MAY_LJMP(hlua_socket_info(L, dst));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002948 xref_unlock(&socket->xref, peer);
2949 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002950}
2951
2952/* Returns information about my connection side. */
2953static int hlua_socket_getsockname(struct lua_State *L)
2954{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002955 struct hlua_socket *socket;
2956 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002957 struct appctx *appctx;
2958 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002959 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002960 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002961
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002962 MAY_LJMP(check_args(L, 1, "getsockname"));
2963
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002964 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002965
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002966 /* Check if we run on the same thread than the xreator thread.
2967 * We cannot access to the socket if the thread is different.
2968 */
2969 if (socket->tid != tid)
2970 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2971
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002972 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002973 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002974 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002975 lua_pushnil(L);
2976 return 1;
2977 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002978
2979 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002980 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002981
Willy Tarreaufd9417b2022-05-18 16:23:22 +02002982 conn = sc_conn(s->scb);
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002983 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002984 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002985 lua_pushnil(L);
2986 return 1;
2987 }
2988
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002989 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002990 xref_unlock(&socket->xref, peer);
2991 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002992}
2993
2994/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002995static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002996 .obj_type = OBJ_TYPE_APPLET,
2997 .name = "<LUA_TCP>",
2998 .fct = hlua_socket_handler,
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002999 .init = hlua_socket_init,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003000 .release = hlua_socket_release,
3001};
3002
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003003__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003004{
3005 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003006 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003007 struct xref *peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02003008 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003009 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003010 struct stream *s;
3011
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003012 /* Get hlua struct, or NULL if we execute from main lua state */
3013 hlua = hlua_gethlua(L);
3014 if (!hlua)
3015 return 0;
3016
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003017 /* Check if we run on the same thread than the xreator thread.
3018 * We cannot access to the socket if the thread is different.
3019 */
3020 if (socket->tid != tid)
3021 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
3022
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003023 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003024 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003025 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003026 lua_pushnil(L);
3027 lua_pushstring(L, "Can't connect");
3028 return 2;
3029 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003030
3031 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
3032 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02003033 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003034
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003035 /* Check if we run on the same thread than the xreator thread.
3036 * We cannot access to the socket if the thread is different.
3037 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003038 if (socket->tid != tid) {
3039 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003040 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003041 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003042
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003043 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003044 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003045 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003046 lua_pushnil(L);
3047 lua_pushstring(L, "Can't connect");
3048 return 2;
3049 }
3050
Willy Tarreau8e7c6e62022-05-18 17:58:02 +02003051 appctx = __sc_appctx(s->scf);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003052
3053 /* Check for connection established. */
Willy Tarreau5321da92022-05-06 11:57:34 +02003054 if (csk_ctx->connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003055 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003056 lua_pushinteger(L, 1);
3057 return 1;
3058 }
3059
Willy Tarreau5321da92022-05-06 11:57:34 +02003060 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003061 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003062 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003063 }
3064 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02003065 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003066 return 0;
3067}
3068
3069/* This function fail or initite the connection. */
3070__LJMP static int hlua_socket_connect(struct lua_State *L)
3071{
3072 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003073 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003074 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01003075 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02003076 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01003077 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003078 int low, high;
3079 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003080 struct xref *peer;
Willy Tarreau3e7be362022-05-27 10:35:27 +02003081 struct stconn *sc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003082 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003083
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003084 if (lua_gettop(L) < 2)
3085 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003086
3087 /* Get args. */
3088 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003089
3090 /* Check if we run on the same thread than the xreator thread.
3091 * We cannot access to the socket if the thread is different.
3092 */
3093 if (socket->tid != tid)
3094 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
3095
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003096 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01003097 if (lua_gettop(L) >= 3) {
3098 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003099 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003100
Tim Duesterhus6edab862018-01-06 19:04:45 +01003101 /* Force the ip to end with a colon, to support IPv6 addresses
3102 * that are not enclosed within square brackets.
3103 */
3104 if (port > 0) {
3105 luaL_buffinit(L, &b);
3106 luaL_addstring(&b, ip);
3107 luaL_addchar(&b, ':');
3108 luaL_pushresult(&b);
3109 ip = lua_tolstring(L, lua_gettop(L), NULL);
3110 }
3111 }
3112
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003113 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003114 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003115 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003116 lua_pushnil(L);
3117 return 1;
3118 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003119
3120 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02003121 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 +02003122 if (!addr) {
3123 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003124 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003125 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02003126
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003127 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003128 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02003129 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003130 if (port == -1) {
3131 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003132 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003133 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02003134 ((struct sockaddr_in *)addr)->sin_port = htons(port);
3135 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003136 if (port == -1) {
3137 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003138 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003139 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02003140 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02003141 }
3142 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02003143
Willy Tarreau5321da92022-05-06 11:57:34 +02003144 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
3145 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02003146 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02003147 s = __sc_strm(sc);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02003148
Willy Tarreau3e7be362022-05-27 10:35:27 +02003149 if (!sockaddr_alloc(&sc_opposite(sc)->dst, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02003150 xref_unlock(&socket->xref, peer);
3151 WILL_LJMP(luaL_error(L, "connect: internal error"));
3152 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003153
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003154 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01003155 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003156 if (!hlua)
3157 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02003158
3159 /* inform the stream that we want to be notified whenever the
3160 * connection completes.
3161 */
Willy Tarreau90e8b452022-05-25 18:21:43 +02003162 applet_need_more_data(appctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02003163 applet_have_more_data(appctx);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02003164 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02003165
Willy Tarreauf31af932020-01-14 09:59:38 +01003166 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02003167
Willy Tarreau5321da92022-05-06 11:57:34 +02003168 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003169 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01003170 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003171 }
3172 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02003173
3174 task_wakeup(s->task, TASK_WOKEN_INIT);
3175 /* Return yield waiting for connection. */
3176
Willy Tarreau9635e032018-10-16 17:52:55 +02003177 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003178
3179 return 0;
3180}
3181
Baptiste Assmann84bb4932015-03-02 21:40:06 +01003182#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003183__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
3184{
3185 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003186 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003187 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003188
3189 MAY_LJMP(check_args(L, 3, "connect_ssl"));
3190 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003191
3192 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003193 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003194 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003195 lua_pushnil(L);
3196 return 1;
3197 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003198
Willy Tarreau0698c802022-05-11 14:09:57 +02003199 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003200
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01003201 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003202 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003203 return MAY_LJMP(hlua_socket_connect(L));
3204}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01003205#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003206
3207__LJMP static int hlua_socket_setoption(struct lua_State *L)
3208{
3209 return 0;
3210}
3211
3212__LJMP static int hlua_socket_settimeout(struct lua_State *L)
3213{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003214 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003215 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02003216 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003217 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003218 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003219
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003220 MAY_LJMP(check_args(L, 2, "settimeout"));
3221
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003222 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02003223
Cyril Bonté7ee465f2018-08-19 22:08:50 +02003224 /* convert the timeout to millis */
3225 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003226
Thierry Fournier17a921b2018-03-08 09:59:02 +01003227 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02003228 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01003229 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
3230
Mark Lakes56cc1252018-03-27 09:48:06 +02003231 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02003232 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02003233
3234 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02003235 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003236 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02003237
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003238 /* Check if we run on the same thread than the xreator thread.
3239 * We cannot access to the socket if the thread is different.
3240 */
3241 if (socket->tid != tid)
3242 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
3243
Mark Lakes56cc1252018-03-27 09:48:06 +02003244 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003245 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003246 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003247 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
3248 WILL_LJMP(lua_error(L));
3249 return 0;
3250 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003251
Willy Tarreau0698c802022-05-11 14:09:57 +02003252 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003253
Cyril Bonté7bb63452018-08-17 23:51:02 +02003254 s->sess->fe->timeout.connect = tmout;
Christopher Faulet5aaacfb2023-02-15 08:13:33 +01003255 s->scf->ioto = tmout;
3256 s->scb->ioto = tmout;
Cyril Bonté7bb63452018-08-17 23:51:02 +02003257
3258 s->task->expire = tick_add_ifset(now_ms, tmout);
3259 task_queue(s->task);
3260
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003261 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003262
Thierry Fourniere9636f12018-03-08 09:54:32 +01003263 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01003264 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003265}
3266
3267__LJMP static int hlua_socket_new(lua_State *L)
3268{
3269 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02003270 struct hlua_csk_ctx *ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003271 struct appctx *appctx;
3272
3273 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003274 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003275 hlua_pusherror(L, "socket: full stack");
3276 goto out_fail_conf;
3277 }
3278
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003279 /* Create the object: obj[0] = userdata. */
3280 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003281 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003282 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003283 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003284 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003285
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003286 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01003287 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01003288 hlua_pusherror(L, "socket: uninitialized pools.");
3289 goto out_fail_conf;
3290 }
3291
Willy Tarreau87b09662015-04-03 00:22:06 +02003292 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003293 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
3294 lua_setmetatable(L, -2);
3295
Willy Tarreaud420a972015-04-06 00:39:18 +02003296 /* Create the applet context */
Christopher Faulet6095d572022-05-16 17:09:48 +02003297 appctx = appctx_new_here(&update_applet, NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003298 if (!appctx) {
3299 hlua_pusherror(L, "socket: out of memory");
Christopher Fauleta9e8b392022-03-23 11:01:09 +01003300 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003301 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003302 ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
3303 ctx->connected = 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02003304 ctx->die = 0;
3305 LIST_INIT(&ctx->wake_on_write);
3306 LIST_INIT(&ctx->wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02003307
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003308 if (appctx_init(appctx) == -1) {
3309 hlua_pusherror(L, "socket: fail to init applet.");
Christopher Faulet13a35e52021-12-20 15:34:16 +01003310 goto out_fail_appctx;
3311 }
3312
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003313 /* Initialise cross reference between stream and Lua socket object. */
Willy Tarreau5321da92022-05-06 11:57:34 +02003314 xref_create(&socket->xref, &ctx->xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003315 return 1;
3316
Christopher Faulet13a35e52021-12-20 15:34:16 +01003317 out_fail_appctx:
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003318 appctx_free_on_early_error(appctx);
Willy Tarreaud420a972015-04-06 00:39:18 +02003319 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003320 WILL_LJMP(lua_error(L));
3321 return 0;
3322}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01003323
3324/*
3325 *
3326 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003327 * Class Channel
3328 *
3329 *
3330 */
3331
3332/* Returns the struct hlua_channel join to the class channel in the
3333 * stack entry "ud" or throws an argument error.
3334 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003335__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003336{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003337 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003338}
3339
Willy Tarreau47860ed2015-03-10 14:07:50 +01003340/* Pushes the channel onto the top of the stack. If the stask does not have a
3341 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003342 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01003343static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003344{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003345 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003346 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003347 return 0;
3348
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003349 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003350 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003351 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003352
3353 /* Pop a class sesison metatable and affect it to the userdata. */
3354 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
3355 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003356 return 1;
3357}
3358
Christopher Faulet9f55a502020-02-25 15:21:02 +01003359/* Helper function returning a filter attached to a channel at the position <ud>
3360 * in the stack, filling the current offset and length of the filter. If no
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05003361 * filter is attached, NULL is returned and <offset> and <len> are not
Christopher Faulet9f55a502020-02-25 15:21:02 +01003362 * initialized.
3363 */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003364static 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 +01003365{
3366 struct filter *filter = NULL;
3367
3368 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
3369 struct hlua_flt_ctx *flt_ctx;
3370
3371 filter = lua_touserdata (L, -1);
3372 flt_ctx = filter->ctx;
3373 if (hlua_filter_from_payload(filter)) {
3374 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
3375 *len = flt_ctx->cur_len[CHN_IDX(chn)];
3376 }
3377 }
3378
3379 lua_pop(L, 1);
3380 return filter;
3381}
3382
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003383/* Copies <len> bytes of data present in the channel's buffer, starting at the
3384* offset <offset>, and put it in a LUA string variable. It is the caller
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003385* responsibility to ensure <len> and <offset> are valid. It always return the
3386* length of the built string. <len> may be 0, in this case, an empty string is
3387* created and 0 is returned.
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003388*/
3389static inline int _hlua_channel_dup(struct channel *chn, lua_State *L, size_t offset, size_t len)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003390{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003391 size_t block1, block2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003392 luaL_Buffer b;
3393
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003394 block1 = len;
3395 if (block1 > b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset)))
3396 block1 = b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset));
3397 block2 = len - block1;
3398
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003399 luaL_buffinit(L, &b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003400 luaL_addlstring(&b, b_peek(&chn->buf, offset), block1);
3401 if (block2)
3402 luaL_addlstring(&b, b_orig(&chn->buf), block2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003403 luaL_pushresult(&b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003404 return len;
3405}
3406
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003407/* Inserts the string <str> to the channel's buffer at the offset <offset>. This
3408 * function returns -1 if data cannot be copied. Otherwise, it returns the
3409 * number of bytes copied.
3410 */
3411static int _hlua_channel_insert(struct channel *chn, lua_State *L, struct ist str, size_t offset)
3412{
3413 int ret = 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003414
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003415 /* Nothing to do, just return */
3416 if (unlikely(istlen(str) == 0))
3417 goto end;
3418
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003419 if (istlen(str) > c_room(chn)) {
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003420 ret = -1;
3421 goto end;
3422 }
3423 ret = b_insert_blk(&chn->buf, offset, istptr(str), istlen(str));
3424
3425 end:
3426 return ret;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003427}
3428
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003429/* Removes <len> bytes of data at the absolute position <offset>.
3430 */
3431static void _hlua_channel_delete(struct channel *chn, size_t offset, size_t len)
3432{
3433 size_t end = offset + len;
3434
3435 if (b_peek(&chn->buf, end) != b_tail(&chn->buf))
3436 b_move(&chn->buf, b_peek_ofs(&chn->buf, end),
3437 b_data(&chn->buf) - end, -len);
3438 b_sub(&chn->buf, len);
3439}
3440
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003441/* Copies input data in the channel's buffer. It is possible to set a specific
3442 * offset (0 by default) and a length (all remaining input data starting for the
3443 * offset by default). If there is not enough input data and more data can be
3444 * received, this function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003445 *
3446 * From an action, All input data are considered. For a filter, the offset and
3447 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003448 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003449__LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003450{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003451 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003452 struct filter *filter;
3453 size_t input, output;
3454 int offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003455
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003456 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003457
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003458 output = co_data(chn);
3459 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003460
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003461 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3462 if (filter && !hlua_filter_from_payload(filter))
3463 WILL_LJMP(lua_error(L));
3464
3465 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003466 if (lua_gettop(L) > 1) {
3467 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3468 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003469 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003470 offset += output;
3471 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003472 lua_pushfstring(L, "offset out of range.");
3473 WILL_LJMP(lua_error(L));
3474 }
3475 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003476 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003477 if (lua_gettop(L) == 3) {
3478 len = MAY_LJMP(luaL_checkinteger(L, 3));
3479 if (!len)
3480 goto dup;
3481 if (len == -1)
3482 len = global.tune.bufsize;
3483 if (len < 0) {
3484 lua_pushfstring(L, "length out of range.");
3485 WILL_LJMP(lua_error(L));
3486 }
3487 }
3488
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003489 /* Wait for more data if possible if no length was specified and there
3490 * is no data or not enough data was received.
3491 */
3492 if (!len || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003493 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3494 /* Yield waiting for more data, as requested */
3495 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_data_yield, TICK_ETERNITY, 0));
3496 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003497
3498 /* Return 'nil' if there is no data and the channel can't receive more data */
3499 if (!len) {
3500 lua_pushnil(L);
3501 return -1;
3502 }
3503
3504 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003505 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003506 }
3507
3508 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003509 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003510 return 1;
3511}
3512
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003513/* Copies the first line (including the trailing LF) of input data in the
3514 * channel's buffer. It is possible to set a specific offset (0 by default) and
3515 * a length (all remaining input data starting for the offset by default). If
3516 * there is not enough input data and more data can be received, the function
3517 * yields. If a length is explicitly specified, no more data are
3518 * copied. Otherwise, if no LF is found and more data can be received, this
3519 * function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003520 *
3521 * From an action, All input data are considered. For a filter, the offset and
3522 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003523 */
3524__LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003525{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003526 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003527 struct filter *filter;
3528 size_t l, input, output;
3529 int offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003530
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003531 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003532 output = co_data(chn);
3533 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003534
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003535 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3536 if (filter && !hlua_filter_from_payload(filter))
3537 WILL_LJMP(lua_error(L));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003538
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003539 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003540 if (lua_gettop(L) > 1) {
3541 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3542 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003543 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003544 offset += output;
3545 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003546 lua_pushfstring(L, "offset out of range.");
3547 WILL_LJMP(lua_error(L));
3548 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003549 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003550
3551 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003552 if (lua_gettop(L) == 3) {
3553 len = MAY_LJMP(luaL_checkinteger(L, 3));
3554 if (!len)
3555 goto dup;
3556 if (len == -1)
3557 len = global.tune.bufsize;
3558 if (len < 0) {
3559 lua_pushfstring(L, "length out of range.");
3560 WILL_LJMP(lua_error(L));
3561 }
3562 }
3563
3564 for (l = 0; l < len; l++) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003565 if (l + offset >= output + input)
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003566 break;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003567 if (*(b_peek(&chn->buf, offset + l)) == '\n') {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003568 len = l+1;
3569 goto dup;
3570 }
3571 }
3572
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003573 /* Wait for more data if possible if no line is found and no length was
3574 * specified or not enough data was received.
3575 */
3576 if (lua_gettop(L) != 3 || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003577 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3578 /* Yield waiting for more data */
3579 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_line_yield, TICK_ETERNITY, 0));
3580 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003581
3582 /* Return 'nil' if there is no data and the channel can't receive more data */
3583 if (!len) {
3584 lua_pushnil(L);
3585 return -1;
3586 }
3587
3588 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003589 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003590 }
3591
3592 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003593 _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003594 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003595}
3596
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003597/* [ DEPRECATED ]
3598 *
3599 * Duplicate all input data foud in the channel's buffer. The data are not
3600 * removed from the buffer. This function relies on _hlua_channel_dup().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003601 *
3602 * From an action, All input data are considered. For a filter, the offset and
3603 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003604 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003605__LJMP static int hlua_channel_dup(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003606{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003607 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003608 struct filter *filter;
3609 size_t offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003610
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003611 MAY_LJMP(check_args(L, 1, "dup"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003612 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003613 if (IS_HTX_STRM(chn_strm(chn))) {
3614 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3615 WILL_LJMP(lua_error(L));
3616 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003617
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003618 offset = co_data(chn);
3619 len = ci_data(chn);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003620
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003621 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3622 if (filter && !hlua_filter_from_payload(filter))
3623 WILL_LJMP(lua_error(L));
3624
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003625 if (!ci_data(chn) && channel_input_closed(chn)) {
3626 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003627 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003628 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003629
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003630 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003631 return 1;
3632}
3633
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003634/* [ DEPRECATED ]
3635 *
3636 * Get all input data foud in the channel's buffer. The data are removed from
3637 * the buffer after the copy. This function relies on _hlua_channel_dup() and
3638 * _hlua_channel_delete().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003639 *
3640 * From an action, All input data are considered. For a filter, the offset and
3641 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003642 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003643__LJMP static int hlua_channel_get(lua_State *L)
3644{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003645 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003646 struct filter *filter;
3647 size_t offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003648 int ret;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003649
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003650 MAY_LJMP(check_args(L, 1, "get"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003651 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3652 if (IS_HTX_STRM(chn_strm(chn))) {
3653 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3654 WILL_LJMP(lua_error(L));
3655 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003656
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003657 offset = co_data(chn);
3658 len = ci_data(chn);
3659
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003660 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3661 if (filter && !hlua_filter_from_payload(filter))
3662 WILL_LJMP(lua_error(L));
3663
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003664 if (!ci_data(chn) && channel_input_closed(chn)) {
3665 lua_pushnil(L);
3666 return 1;
3667 }
3668
3669 ret = _hlua_channel_dup(chn, L, offset, len);
3670 _hlua_channel_delete(chn, offset, ret);
3671 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003672}
3673
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003674/* This functions consumes and returns one line. If the channel is closed,
3675 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003676 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003677 * value.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003678 *
3679 * From an action, All input data are considered. For a filter, the offset and
3680 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003681 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003682__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003683{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003684 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003685 struct filter *filter;
3686 size_t l, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003687 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003688
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003689 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003690
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003691 offset = co_data(chn);
3692 len = ci_data(chn);
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003693
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003694 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3695 if (filter && !hlua_filter_from_payload(filter))
3696 WILL_LJMP(lua_error(L));
3697
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003698 if (!ci_data(chn) && channel_input_closed(chn)) {
3699 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003700 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003701 }
3702
3703 for (l = 0; l < len; l++) {
3704 if (*(b_peek(&chn->buf, offset+l)) == '\n') {
3705 len = l+1;
3706 goto dup;
3707 }
3708 }
3709
3710 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3711 /* Yield waiting for more data */
3712 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
3713 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003714
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003715 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003716 ret = _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003717 _hlua_channel_delete(chn, offset, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003718 return 1;
3719}
3720
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003721/* [ DEPRECATED ]
3722 *
3723 * Check arguments for the function "hlua_channel_getline_yield".
3724 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003725__LJMP static int hlua_channel_getline(lua_State *L)
3726{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003727 struct channel *chn;
3728
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003729 MAY_LJMP(check_args(L, 1, "getline"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003730 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3731 if (IS_HTX_STRM(chn_strm(chn))) {
3732 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3733 WILL_LJMP(lua_error(L));
3734 }
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003735 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3736}
3737
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003738/* Retrieves a given amount of input data at the given offset. By default all
3739 * available input data are returned. The offset may be negactive to start from
3740 * the end of input data. The length may be -1 to set it to the maximum buffer
3741 * size.
3742 */
3743__LJMP static int hlua_channel_get_data(lua_State *L)
3744{
3745 struct channel *chn;
3746
3747 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3748 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
3749 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3750 if (IS_HTX_STRM(chn_strm(chn))) {
3751 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3752 WILL_LJMP(lua_error(L));
3753 }
3754 return MAY_LJMP(hlua_channel_get_data_yield(L, 0, 0));
3755}
3756
3757/* Retrieves a given amount of input data at the given offset. By default all
3758 * available input data are returned. The offset may be negactive to start from
3759 * the end of input data. The length may be -1 to set it to the maximum buffer
3760 * size.
3761 */
3762__LJMP static int hlua_channel_get_line(lua_State *L)
3763{
3764 struct channel *chn;
3765
3766 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3767 WILL_LJMP(luaL_error(L, "'line' expects at most 2 arguments"));
3768 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3769 if (IS_HTX_STRM(chn_strm(chn))) {
3770 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3771 WILL_LJMP(lua_error(L));
3772 }
3773 return MAY_LJMP(hlua_channel_get_line_yield(L, 0, 0));
3774}
3775
3776/* Appends a string into the input side of channel. It returns the length of the
3777 * written string, or -1 if the channel is closed or if the buffer size is too
3778 * little for the data. 0 may be returned if nothing is copied. This function
3779 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003780 *
3781 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003782 */
Christopher Faulet23976d92021-08-06 09:59:49 +02003783__LJMP static int hlua_channel_append(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003784{
Christopher Faulet23976d92021-08-06 09:59:49 +02003785 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003786 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003787 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003788 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003789 int ret;
Christopher Faulet23976d92021-08-06 09:59:49 +02003790
3791 MAY_LJMP(check_args(L, 2, "append"));
3792 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003793 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003794 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003795 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003796 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003797 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003798
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003799 offset = co_data(chn);
3800 len = ci_data(chn);
3801
3802 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3803 if (filter && !hlua_filter_from_payload(filter))
3804 WILL_LJMP(lua_error(L));
3805
3806 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3807 if (ret > 0 && filter) {
3808 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3809
3810 flt_update_offsets(filter, chn, ret);
3811 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3812 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003813 lua_pushinteger(L, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003814 return 1;
3815}
3816
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003817/* Prepends a string into the input side of channel. It returns the length of the
3818 * written string, or -1 if the channel is closed or if the buffer size is too
3819 * little for the data. 0 may be returned if nothing is copied. This function
3820 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003821 *
3822 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003823 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003824__LJMP static int hlua_channel_prepend(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003825{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003826 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003827 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003828 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003829 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003830 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003831
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003832 MAY_LJMP(check_args(L, 2, "prepend"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003833 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003834 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3835 if (IS_HTX_STRM(chn_strm(chn))) {
3836 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3837 WILL_LJMP(lua_error(L));
3838 }
3839
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003840 offset = co_data(chn);
3841 len = ci_data(chn);
3842
3843 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3844 if (filter && !hlua_filter_from_payload(filter))
3845 WILL_LJMP(lua_error(L));
3846
3847 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3848 if (ret > 0 && filter) {
3849 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3850
3851 flt_update_offsets(filter, chn, ret);
3852 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3853 }
3854
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003855 lua_pushinteger(L, ret);
3856 return 1;
3857}
3858
3859/* Inserts a given amount of input data at the given offset by a string
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003860 * content. By default the string is appended in front of input data. It
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003861 * returns the length of the written string, or -1 if the channel is closed or
3862 * if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003863 *
3864 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003865 */
3866__LJMP static int hlua_channel_insert_data(lua_State *L)
3867{
3868 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003869 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003870 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003871 size_t sz, input, output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003872 int ret, offset;
3873
3874 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
3875 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
3876 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3877 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003878
3879 output = co_data(chn);
3880 input = ci_data(chn);
3881
3882 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3883 if (filter && !hlua_filter_from_payload(filter))
3884 WILL_LJMP(lua_error(L));
3885
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003886 offset = output;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003887 if (lua_gettop(L) > 2) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003888 offset = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003889 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003890 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003891 offset += output;
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003892 if (offset > output + input) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003893 lua_pushfstring(L, "offset out of range.");
3894 WILL_LJMP(lua_error(L));
3895 }
3896 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003897 if (IS_HTX_STRM(chn_strm(chn))) {
3898 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3899 WILL_LJMP(lua_error(L));
3900 }
3901
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003902 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3903 if (ret > 0 && filter) {
3904 struct hlua_flt_ctx *flt_ctx = filter->ctx;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003905
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003906 flt_update_offsets(filter, chn, ret);
3907 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003908 }
3909
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003910 lua_pushinteger(L, ret);
3911 return 1;
3912}
3913/* Replaces a given amount of input data at the given offset by a string
3914 * content. By default all remaining data are removed (offset = 0 and len =
3915 * -1). It returns the length of the written string, or -1 if the channel is
3916 * closed or if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003917 *
3918 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003919 */
3920__LJMP static int hlua_channel_set_data(lua_State *L)
3921{
3922 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003923 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003924 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003925 size_t sz, input, output;
3926 int ret, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003927
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003928 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
3929 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
3930 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3931 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003932
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003933 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003934 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003935 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003936 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003937
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003938 output = co_data(chn);
3939 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003940
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003941 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3942 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003943 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003944
3945 offset = output;
3946 if (lua_gettop(L) > 2) {
3947 offset = MAY_LJMP(luaL_checkinteger(L, 3));
3948 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003949 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003950 offset += output;
3951 if (offset < output || offset > input + output) {
3952 lua_pushfstring(L, "offset out of range.");
3953 WILL_LJMP(lua_error(L));
3954 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003955 }
3956
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003957 len = output + input - offset;
3958 if (lua_gettop(L) == 4) {
3959 len = MAY_LJMP(luaL_checkinteger(L, 4));
3960 if (!len)
3961 goto set;
3962 if (len == -1)
3963 len = output + input - offset;
3964 if (len < 0 || offset + len > output + input) {
3965 lua_pushfstring(L, "length out of range.");
3966 WILL_LJMP(lua_error(L));
3967 }
3968 }
3969
3970 set:
Christopher Faulet23976d92021-08-06 09:59:49 +02003971 /* Be sure we can copied the string once input data will be removed. */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003972 if (sz > c_room(chn) + len)
Christopher Faulet23976d92021-08-06 09:59:49 +02003973 lua_pushinteger(L, -1);
3974 else {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003975 _hlua_channel_delete(chn, offset, len);
3976 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3977 if (filter) {
3978 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3979
3980 len -= (ret > 0 ? ret : 0);
3981 flt_update_offsets(filter, chn, -len);
3982 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3983 }
3984
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003985 lua_pushinteger(L, ret);
Christopher Faulet23976d92021-08-06 09:59:49 +02003986 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003987 return 1;
3988}
3989
3990/* Removes a given amount of input data at the given offset. By default all
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003991 * input data are removed (offset = 0 and len = -1). It returns the amount of
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003992 * the removed data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003993 *
3994 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003995 */
3996__LJMP static int hlua_channel_del_data(lua_State *L)
3997{
3998 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003999 struct filter *filter;
4000 size_t input, output;
4001 int offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004002
4003 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
4004 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
4005 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004006
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004007 if (IS_HTX_STRM(chn_strm(chn))) {
4008 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
4009 WILL_LJMP(lua_error(L));
4010 }
4011
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004012 output = co_data(chn);
4013 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004014
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004015 filter = hlua_channel_filter(L, 1, chn, &output, &input);
4016 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004017 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004018
4019 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00004020 if (lua_gettop(L) > 1) {
4021 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004022 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02004023 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004024 offset += output;
4025 if (offset < output || offset > input + output) {
4026 lua_pushfstring(L, "offset out of range.");
4027 WILL_LJMP(lua_error(L));
4028 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004029 }
4030
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004031 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00004032 if (lua_gettop(L) == 3) {
4033 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004034 if (!len)
4035 goto end;
4036 if (len == -1)
4037 len = output + input - offset;
4038 if (len < 0 || offset + len > output + input) {
4039 lua_pushfstring(L, "length out of range.");
4040 WILL_LJMP(lua_error(L));
4041 }
4042 }
4043
4044 _hlua_channel_delete(chn, offset, len);
4045 if (filter) {
4046 struct hlua_flt_ctx *flt_ctx = filter->ctx;
4047
4048 flt_update_offsets(filter, chn, -len);
4049 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
4050 }
4051
4052 end:
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004053 lua_pushinteger(L, len);
Christopher Faulet23976d92021-08-06 09:59:49 +02004054 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004055}
4056
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004057/* Append data in the output side of the buffer. This data is immediately
4058 * sent. The function returns the amount of data written. If the buffer
4059 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004060 * if the channel is closed.
4061 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004062__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004063{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004064 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004065 struct filter *filter;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004066 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004067 size_t offset, len, sz;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004068 int l, ret;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01004069 struct hlua *hlua;
4070
4071 /* Get hlua struct, or NULL if we execute from main lua state */
4072 hlua = hlua_gethlua(L);
4073 if (!hlua) {
4074 lua_pushnil(L);
4075 return 1;
4076 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004077
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004078 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4079 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
4080 l = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Faulet3f829a42018-12-13 21:56:45 +01004081
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004082 offset = co_data(chn);
4083 len = ci_data(chn);
4084
4085 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
4086 if (filter && !hlua_filter_from_payload(filter))
4087 WILL_LJMP(lua_error(L));
4088
4089
Willy Tarreau47860ed2015-03-10 14:07:50 +01004090 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004091 lua_pushinteger(L, -1);
4092 return 1;
4093 }
4094
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004095 len = c_room(chn);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004096 if (len > sz -l) {
4097 if (filter) {
4098 lua_pushinteger(L, -1);
4099 return 1;
4100 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004101 len = sz - l;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004102 }
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01004103
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004104 ret = _hlua_channel_insert(chn, L, ist2(str, len), offset);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004105 if (ret == -1) {
4106 lua_pop(L, 1);
4107 lua_pushinteger(L, -1);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01004108 return 1;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004109 }
4110 if (ret) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004111 if (filter) {
4112 struct hlua_flt_ctx *flt_ctx = filter->ctx;
4113
4114
4115 flt_update_offsets(filter, chn, ret);
4116 FLT_OFF(filter, chn) += ret;
4117 flt_ctx->cur_off[CHN_IDX(chn)] += ret;
4118 }
4119 else
4120 c_adv(chn, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004121
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004122 l += ret;
4123 lua_pop(L, 1);
4124 lua_pushinteger(L, l);
4125 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004126
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004127 if (l < sz) {
4128 /* Yield only if the channel's output is not empty.
4129 * Otherwise it means we cannot add more data. */
4130 if (co_data(chn) == 0 || HLUA_CANT_YIELD(hlua_gethlua(L)))
Christopher Faulet2e60aa42021-08-05 11:58:37 +02004131 return 1;
4132
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004133 /* If we are waiting for space in the response buffer, we
4134 * must set the flag WAKERESWR. This flag required the task
4135 * wake up if any activity is detected on the response buffer.
4136 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01004137 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004138 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01004139 else
4140 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02004141 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004142 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004143
4144 return 1;
4145}
4146
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004147/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004148 * yield the LUA process, and resume it without checking the
4149 * input arguments.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004150 *
4151 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004152 */
4153__LJMP static int hlua_channel_send(lua_State *L)
4154{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004155 struct channel *chn;
4156
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004157 MAY_LJMP(check_args(L, 2, "send"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004158 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4159 if (IS_HTX_STRM(chn_strm(chn))) {
4160 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
4161 WILL_LJMP(lua_error(L));
4162 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004163 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004164 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004165}
4166
4167/* This function forward and amount of butes. The data pass from
4168 * the input side of the buffer to the output side, and can be
4169 * forwarded. This function never fails.
4170 *
4171 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004172 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004173 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004174__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004175{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004176 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004177 struct filter *filter;
4178 size_t offset, len, fwd;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004179 int l, max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01004180 struct hlua *hlua;
4181
4182 /* Get hlua struct, or NULL if we execute from main lua state */
4183 hlua = hlua_gethlua(L);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004184 if (!hlua) {
4185 lua_pushnil(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01004186 return 1;
Thierry Fournier77016da2020-08-15 14:35:51 +02004187 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01004188
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004189 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004190 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004191 l = MAY_LJMP(luaL_checkinteger(L, -1));
4192
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004193 offset = co_data(chn);
4194 len = ci_data(chn);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004195
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004196 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
4197 if (filter && !hlua_filter_from_payload(filter))
4198 WILL_LJMP(lua_error(L));
4199
4200 max = fwd - l;
4201 if (max > len)
4202 max = len;
4203
4204 if (filter) {
4205 struct hlua_flt_ctx *flt_ctx = filter->ctx;
4206
4207 FLT_OFF(filter, chn) += max;
4208 flt_ctx->cur_off[CHN_IDX(chn)] += max;
4209 flt_ctx->cur_len[CHN_IDX(chn)] -= max;
4210 }
4211 else
4212 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004213
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004214 l += max;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004215 lua_pop(L, 1);
4216 lua_pushinteger(L, l);
4217
4218 /* Check if it miss bytes to forward. */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004219 if (l < fwd) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004220 /* The the input channel or the output channel are closed, we
4221 * must return the amount of data forwarded.
4222 */
Christopher Faulet2e60aa42021-08-05 11:58:37 +02004223 if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L)))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004224 return 1;
4225
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004226 /* If we are waiting for space data in the response buffer, we
4227 * must set the flag WAKERESWR. This flag required the task
4228 * wake up if any activity is detected on the response buffer.
4229 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01004230 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004231 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01004232 else
4233 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004234
Ilya Shipitsin4a689da2022-10-29 09:34:32 +05004235 /* Otherwise, we can yield waiting for new data in the input side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02004236 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004237 }
4238
4239 return 1;
4240}
4241
4242/* Just check the input and prepare the stack for the previous
4243 * function "hlua_channel_forward_yield"
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004244 *
4245 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004246 */
4247__LJMP static int hlua_channel_forward(lua_State *L)
4248{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004249 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004250
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004251 MAY_LJMP(check_args(L, 2, "forward"));
4252 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4253 if (IS_HTX_STRM(chn_strm(chn))) {
4254 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
4255 WILL_LJMP(lua_error(L));
4256 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004257 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004258 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004259}
4260
4261/* Just returns the number of bytes available in the input
4262 * side of the buffer. This function never fails.
4263 */
4264__LJMP static int hlua_channel_get_in_len(lua_State *L)
4265{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004266 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004267 struct filter *filter;
4268 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004269
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004270 MAY_LJMP(check_args(L, 1, "input"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004271 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004272
4273 output = co_data(chn);
4274 input = ci_data(chn);
4275 filter = hlua_channel_filter(L, 1, chn, &output, &input);
4276 if (filter || !IS_HTX_STRM(chn_strm(chn)))
4277 lua_pushinteger(L, input);
4278 else {
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004279 struct htx *htx = htxbuf(&chn->buf);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004280
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004281 lua_pushinteger(L, htx->data - co_data(chn));
4282 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004283 return 1;
4284}
4285
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004286/* Returns true if the channel is full. */
4287__LJMP static int hlua_channel_is_full(lua_State *L)
4288{
4289 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004290
4291 MAY_LJMP(check_args(L, 1, "is_full"));
4292 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01004293 /* ignore the reserve, we are not on a producer side (ie in an
4294 * applet).
4295 */
4296 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004297 return 1;
4298}
4299
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004300/* Returns true if the channel may still receive data. */
4301__LJMP static int hlua_channel_may_recv(lua_State *L)
4302{
4303 struct channel *chn;
4304
4305 MAY_LJMP(check_args(L, 1, "may_recv"));
4306 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4307 lua_pushboolean(L, (!channel_input_closed(chn) && channel_may_recv(chn)));
4308 return 1;
4309}
4310
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01004311/* Returns true if the channel is the response channel. */
4312__LJMP static int hlua_channel_is_resp(lua_State *L)
4313{
4314 struct channel *chn;
4315
4316 MAY_LJMP(check_args(L, 1, "is_resp"));
4317 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4318
4319 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
4320 return 1;
4321}
4322
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004323/* Just returns the number of bytes available in the output
4324 * side of the buffer. This function never fails.
4325 */
4326__LJMP static int hlua_channel_get_out_len(lua_State *L)
4327{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004328 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004329 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004330
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004331 MAY_LJMP(check_args(L, 1, "output"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004332 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004333
4334 output = co_data(chn);
4335 input = ci_data(chn);
4336 hlua_channel_filter(L, 1, chn, &output, &input);
4337
4338 lua_pushinteger(L, output);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004339 return 1;
4340}
4341
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004342/*
4343 *
4344 *
4345 * Class Fetches
4346 *
4347 *
4348 */
4349
4350/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004351 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004352 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004353__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004354{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004355 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004356}
4357
4358/* This function creates and push in the stack a fetch object according
4359 * with a current TXN.
4360 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004361static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004362{
Willy Tarreau7073c472015-04-06 11:15:40 +02004363 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004364
4365 /* Check stack size. */
4366 if (!lua_checkstack(L, 3))
4367 return 0;
4368
4369 /* Create the object: obj[0] = userdata.
4370 * Note that the base of the Fetches object is the
4371 * transaction object.
4372 */
4373 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004374 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004375 lua_rawseti(L, -2, 0);
4376
Willy Tarreau7073c472015-04-06 11:15:40 +02004377 hsmp->s = txn->s;
4378 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004379 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004380 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004381
4382 /* Pop a class sesison metatable and affect it to the userdata. */
4383 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
4384 lua_setmetatable(L, -2);
4385
4386 return 1;
4387}
4388
4389/* This function is an LUA binding. It is called with each sample-fetch.
4390 * It uses closure argument to store the associated sample-fetch. It
4391 * returns only one argument or throws an error. An error is thrown
4392 * only if an error is encountered during the argument parsing. If
4393 * the "sample-fetch" function fails, nil is returned.
4394 */
4395__LJMP static int hlua_run_sample_fetch(lua_State *L)
4396{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004397 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01004398 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004399 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004400 int i;
4401 struct sample smp;
4402
4403 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004404 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004405
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004406 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004407 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004408
Thierry FOURNIERca988662015-12-20 18:43:03 +01004409 /* Check execution authorization. */
4410 if (f->use & SMP_USE_HTTP_ANY &&
4411 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
4412 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
4413 "is not available in Lua services", f->kw);
4414 WILL_LJMP(lua_error(L));
4415 }
4416
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004417 /* Get extra arguments. */
4418 for (i = 0; i < lua_gettop(L) - 1; i++) {
4419 if (i >= ARGM_NBARGS)
4420 break;
4421 hlua_lua2arg(L, i + 2, &args[i]);
4422 }
4423 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004424 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004425
4426 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004427 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004428
4429 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01004430 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004431 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004432 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004433 }
4434
4435 /* Initialise the sample. */
4436 memset(&smp, 0, sizeof(smp));
4437
4438 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01004439 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02004440 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004441 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004442 lua_pushstring(L, "");
4443 else
4444 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004445 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004446 }
4447
4448 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004449 if (hsmp->flags & HLUA_F_AS_STRING)
Aurelien DARRAGON742b1a82023-05-17 10:38:50 +02004450 MAY_LJMP(hlua_smp2lua_str(L, &smp));
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004451 else
Aurelien DARRAGON41217722023-05-17 10:44:47 +02004452 MAY_LJMP(hlua_smp2lua(L, &smp));
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004453
4454 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004455 free_args(args);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004456 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004457
4458 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004459 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004460 WILL_LJMP(lua_error(L));
4461 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004462}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004463
4464/*
4465 *
4466 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004467 * Class Converters
4468 *
4469 *
4470 */
4471
4472/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004473 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004474 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004475__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004476{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004477 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004478}
4479
4480/* This function creates and push in the stack a Converters object
4481 * according with a current TXN.
4482 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004483static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004484{
Willy Tarreau7073c472015-04-06 11:15:40 +02004485 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004486
4487 /* Check stack size. */
4488 if (!lua_checkstack(L, 3))
4489 return 0;
4490
4491 /* Create the object: obj[0] = userdata.
4492 * Note that the base of the Converters object is the
4493 * same than the TXN object.
4494 */
4495 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004496 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004497 lua_rawseti(L, -2, 0);
4498
Willy Tarreau7073c472015-04-06 11:15:40 +02004499 hsmp->s = txn->s;
4500 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004501 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004502 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004503
Willy Tarreau87b09662015-04-03 00:22:06 +02004504 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004505 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
4506 lua_setmetatable(L, -2);
4507
4508 return 1;
4509}
4510
4511/* This function is an LUA binding. It is called with each converter.
4512 * It uses closure argument to store the associated converter. It
4513 * returns only one argument or throws an error. An error is thrown
4514 * only if an error is encountered during the argument parsing. If
4515 * the converter function function fails, nil is returned.
4516 */
4517__LJMP static int hlua_run_sample_conv(lua_State *L)
4518{
Willy Tarreauda5f1082015-04-06 11:17:13 +02004519 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004520 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004521 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004522 int i;
4523 struct sample smp;
4524
4525 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004526 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004527
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004528 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004529 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004530
4531 /* Get extra arguments. */
4532 for (i = 0; i < lua_gettop(L) - 2; i++) {
4533 if (i >= ARGM_NBARGS)
4534 break;
4535 hlua_lua2arg(L, i + 3, &args[i]);
4536 }
4537 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004538 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004539
4540 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004541 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004542
4543 /* Run the special args checker. */
4544 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
4545 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004546 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004547 }
4548
4549 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004550 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004551 if (!hlua_lua2smp(L, 2, &smp)) {
4552 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004553 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004554 }
4555
Willy Tarreau1777ea62016-03-10 16:15:46 +01004556 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
4557
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004558 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004559 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004560 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004561 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004562 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004563 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004564 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
4565 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004566 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004567 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004568 }
4569
4570 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02004571 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004572 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004573 lua_pushstring(L, "");
4574 else
Willy Tarreaua678b432015-08-28 10:14:59 +02004575 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004576 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004577 }
4578
4579 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004580 if (hsmp->flags & HLUA_F_AS_STRING)
Aurelien DARRAGON742b1a82023-05-17 10:38:50 +02004581 MAY_LJMP(hlua_smp2lua_str(L, &smp));
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004582 else
Aurelien DARRAGON41217722023-05-17 10:44:47 +02004583 MAY_LJMP(hlua_smp2lua(L, &smp));
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004584 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004585 free_args(args);
Willy Tarreaua678b432015-08-28 10:14:59 +02004586 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004587
4588 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004589 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004590 WILL_LJMP(lua_error(L));
4591 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004592}
4593
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004594/*
4595 *
4596 *
4597 * Class AppletTCP
4598 *
4599 *
4600 */
4601
4602/* Returns a struct hlua_txn if the stack entry "ud" is
4603 * a class stream, otherwise it throws an error.
4604 */
4605__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
4606{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004607 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004608}
4609
4610/* This function creates and push in the stack an Applet object
4611 * according with a current TXN.
4612 */
4613static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
4614{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004615 struct hlua_appctx *luactx;
Willy Tarreau0698c802022-05-11 14:09:57 +02004616 struct stream *s = appctx_strm(ctx);
Christopher Faulet2da02ae2022-02-24 13:45:27 +01004617 struct proxy *p;
4618
4619 ALREADY_CHECKED(s);
4620 p = s->be;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004621
4622 /* Check stack size. */
4623 if (!lua_checkstack(L, 3))
4624 return 0;
4625
4626 /* Create the object: obj[0] = userdata.
4627 * Note that the base of the Converters object is the
4628 * same than the TXN object.
4629 */
4630 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004631 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004632 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004633 luactx->appctx = ctx;
4634 luactx->htxn.s = s;
4635 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004636
4637 /* Create the "f" field that contains a list of fetches. */
4638 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004639 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004640 return 0;
4641 lua_settable(L, -3);
4642
4643 /* Create the "sf" field that contains a list of stringsafe fetches. */
4644 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004645 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004646 return 0;
4647 lua_settable(L, -3);
4648
4649 /* Create the "c" field that contains a list of converters. */
4650 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004651 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004652 return 0;
4653 lua_settable(L, -3);
4654
4655 /* Create the "sc" field that contains a list of stringsafe converters. */
4656 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004657 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004658 return 0;
4659 lua_settable(L, -3);
4660
4661 /* Pop a class stream metatable and affect it to the table. */
4662 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
4663 lua_setmetatable(L, -2);
4664
4665 return 1;
4666}
4667
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004668__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
4669{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004670 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004671 struct stream *s;
4672 const char *name;
4673 size_t len;
4674 struct sample smp;
4675
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004676 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4677 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004678
4679 /* It is useles to retrieve the stream, but this function
4680 * runs only in a stream context.
4681 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004682 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004683 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004684 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004685
4686 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004687 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004688 hlua_lua2smp(L, 3, &smp);
4689
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02004690 /* Store the sample in a variable. We don't need to dup the smp, vars API
4691 * already takes care of duplicating dynamic var data.
4692 */
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004693 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004694
4695 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4696 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4697 else
4698 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4699
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004700 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004701}
4702
4703__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
4704{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004705 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004706 struct stream *s;
4707 const char *name;
4708 size_t len;
4709 struct sample smp;
4710
4711 MAY_LJMP(check_args(L, 2, "unset_var"));
4712
4713 /* It is useles to retrieve the stream, but this function
4714 * runs only in a stream context.
4715 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004716 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004717 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004718 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004719
4720 /* Unset the variable. */
4721 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004722 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4723 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004724}
4725
4726__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
4727{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004728 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004729 struct stream *s;
4730 const char *name;
4731 size_t len;
4732 struct sample smp;
4733
4734 MAY_LJMP(check_args(L, 2, "get_var"));
4735
4736 /* It is useles to retrieve the stream, but this function
4737 * runs only in a stream context.
4738 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004739 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004740 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004741 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004742
4743 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02004744 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004745 lua_pushnil(L);
4746 return 1;
4747 }
4748
Aurelien DARRAGON41217722023-05-17 10:44:47 +02004749 return MAY_LJMP(hlua_smp2lua(L, &smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004750}
4751
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004752__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
4753{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004754 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4755 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004756 struct hlua *hlua;
4757
4758 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004759 if (!s->hlua)
4760 return 0;
4761 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004762
4763 MAY_LJMP(check_args(L, 2, "set_priv"));
4764
4765 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004766 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004767
4768 /* Get and store new value. */
4769 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4770 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4771
4772 return 0;
4773}
4774
4775__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
4776{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004777 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4778 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004779 struct hlua *hlua;
4780
4781 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004782 if (!s->hlua) {
4783 lua_pushnil(L);
4784 return 1;
4785 }
4786 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004787
4788 /* Push configuration index in the stack. */
4789 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4790
4791 return 1;
4792}
4793
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004794/* If expected data not yet available, it returns a yield. This function
4795 * consumes the data in the buffer. It returns a string containing the
4796 * data. This string can be empty.
4797 */
4798__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
4799{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004800 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004801 struct stconn *sc = appctx_sc(luactx->appctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004802 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004803 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004804 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004805 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004806 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004807
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004808 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004809 ret = co_getline_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004810
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004811 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004812 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004813 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004814 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004815 }
4816
4817 /* End of data: commit the total strings and return. */
4818 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004819 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004820 return 1;
4821 }
4822
4823 /* Ensure that the block 2 length is usable. */
4824 if (ret == 1)
4825 len2 = 0;
4826
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004827 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004828 luaL_addlstring(&luactx->b, blk1, len1);
4829 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004830
4831 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004832 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004833 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004834 return 1;
4835}
4836
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004837/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004838__LJMP static int hlua_applet_tcp_getline(lua_State *L)
4839{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004840 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004841
4842 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004843 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004844
4845 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
4846}
4847
4848/* If expected data not yet available, it returns a yield. This function
4849 * consumes the data in the buffer. It returns a string containing the
4850 * data. This string can be empty.
4851 */
4852__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
4853{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004854 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004855 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004856 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004857 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004858 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004859 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004860 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004861 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004862
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004863 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004864 ret = co_getblk_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004865
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004866 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004867 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004868 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004869 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004870 }
4871
4872 /* End of data: commit the total strings and return. */
4873 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004874 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004875 return 1;
4876 }
4877
4878 /* Ensure that the block 2 length is usable. */
4879 if (ret == 1)
4880 len2 = 0;
4881
4882 if (len == -1) {
4883
4884 /* If len == -1, catenate all the data avalaile and
4885 * yield because we want to get all the data until
4886 * the end of data stream.
4887 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004888 luaL_addlstring(&luactx->b, blk1, len1);
4889 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004890 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004891 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004892 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004893
4894 } else {
4895
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004896 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004897 if (len1 > len)
4898 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004899 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004900 len -= len1;
4901
4902 /* Copy the second block. */
4903 if (len2 > len)
4904 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004905 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004906 len -= len2;
4907
4908 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004909 co_skip(sc_oc(sc), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004910
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004911 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004912 if (len > 0) {
4913 lua_pushinteger(L, len);
4914 lua_replace(L, 2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004915 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004916 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004917 }
4918
4919 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004920 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004921 return 1;
4922 }
4923
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004924 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004925 hlua_pusherror(L, "Lua: internal error");
4926 WILL_LJMP(lua_error(L));
4927 return 0;
4928}
4929
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004930/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004931__LJMP static int hlua_applet_tcp_recv(lua_State *L)
4932{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004933 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004934 int len = -1;
4935
4936 if (lua_gettop(L) > 2)
4937 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4938 if (lua_gettop(L) >= 2) {
4939 len = MAY_LJMP(luaL_checkinteger(L, 2));
4940 lua_pop(L, 1);
4941 }
4942
4943 /* Confirm or set the required length */
4944 lua_pushinteger(L, len);
4945
4946 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004947 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004948
4949 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
4950}
4951
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004952/* Append data in the output side of the buffer. This data is immediately
4953 * sent. The function returns the amount of data written. If the buffer
4954 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004955 * if the channel is closed.
4956 */
4957__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4958{
4959 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004960 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004961 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4962 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004963 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004964 struct channel *chn = sc_ic(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004965 int max;
4966
4967 /* Get the max amount of data which can write as input in the channel. */
4968 max = channel_recv_max(chn);
4969 if (max > (len - l))
4970 max = len - l;
4971
4972 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004973 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004974
4975 /* update counters. */
4976 l += max;
4977 lua_pop(L, 1);
4978 lua_pushinteger(L, l);
4979
4980 /* If some data is not send, declares the situation to the
4981 * applet, and returns a yield.
4982 */
4983 if (l < len) {
Christopher Faulet7b3d38a2023-05-05 11:28:45 +02004984 sc_need_room(sc, channel_recv_max(chn) + 1);
Willy Tarreau9635e032018-10-16 17:52:55 +02004985 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004986 }
4987
4988 return 1;
4989}
4990
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004991/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004992 * yield the LUA process, and resume it without checking the
4993 * input arguments.
4994 */
4995__LJMP static int hlua_applet_tcp_send(lua_State *L)
4996{
4997 MAY_LJMP(check_args(L, 2, "send"));
4998 lua_pushinteger(L, 0);
4999
5000 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
5001}
5002
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005003/*
5004 *
5005 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005006 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005007 *
5008 *
5009 */
5010
5011/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02005012 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005013 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005014__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005015{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02005016 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005017}
5018
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005019/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005020 * according with a current TXN.
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005021 * It relies on the caller to have already reserved the room in ctx->svcctx
5022 * for the local storage of hlua_http_ctx.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005023 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005024static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005025{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005026 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreau7e702d12021-04-28 17:59:21 +02005027 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01005028 struct hlua_txn htxn;
Willy Tarreau0698c802022-05-11 14:09:57 +02005029 struct stream *s = appctx_strm(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005030 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02005031 struct htx *htx;
5032 struct htx_blk *blk;
5033 struct htx_sl *sl;
5034 struct ist path;
5035 unsigned long long len = 0;
5036 int32_t pos;
Amaury Denoyellec453f952021-07-06 11:40:12 +02005037 struct http_uri_parser parser;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005038
5039 /* Check stack size. */
5040 if (!lua_checkstack(L, 3))
5041 return 0;
5042
5043 /* Create the object: obj[0] = userdata.
5044 * Note that the base of the Converters object is the
5045 * same than the TXN object.
5046 */
5047 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02005048 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005049 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02005050 luactx->appctx = ctx;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005051 http_ctx->status = 200; /* Default status code returned. */
5052 http_ctx->reason = NULL; /* Use default reason based on status */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005053 luactx->htxn.s = s;
5054 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005055
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005056 /* Create the "f" field that contains a list of fetches. */
5057 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02005058 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005059 return 0;
5060 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005061
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005062 /* Create the "sf" field that contains a list of stringsafe fetches. */
5063 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02005064 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005065 return 0;
5066 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005067
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005068 /* Create the "c" field that contains a list of converters. */
5069 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02005070 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005071 return 0;
5072 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005073
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005074 /* Create the "sc" field that contains a list of stringsafe converters. */
5075 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02005076 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005077 return 0;
5078 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02005079
Christopher Fauleta2097962019-07-15 16:25:33 +02005080 htx = htxbuf(&s->req.buf);
5081 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01005082 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02005083 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005084
Christopher Fauleta2097962019-07-15 16:25:33 +02005085 /* Stores the request method. */
5086 lua_pushstring(L, "method");
5087 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
5088 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005089
Christopher Fauleta2097962019-07-15 16:25:33 +02005090 /* Stores the http version. */
5091 lua_pushstring(L, "version");
5092 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
5093 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005094
Christopher Fauleta2097962019-07-15 16:25:33 +02005095 /* creates an array of headers. hlua_http_get_headers() crates and push
5096 * the array on the top of the stack.
5097 */
5098 lua_pushstring(L, "headers");
5099 htxn.s = s;
5100 htxn.p = px;
5101 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005102 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02005103 return 0;
5104 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005105
Amaury Denoyellec453f952021-07-06 11:40:12 +02005106 parser = http_uri_parser_init(htx_sl_req_uri(sl));
5107 path = http_parse_path(&parser);
Tim Duesterhused526372020-03-05 17:56:33 +01005108 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02005109 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005110
Christopher Fauleta2097962019-07-15 16:25:33 +02005111 p = path.ptr;
Tim Duesterhus4c8f75f2021-11-06 15:14:44 +01005112 end = istend(path);
Christopher Fauleta2097962019-07-15 16:25:33 +02005113 q = p;
5114 while (q < end && *q != '?')
5115 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005116
Thierry FOURNIER7d388632017-02-22 02:06:16 +01005117 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02005118 lua_pushstring(L, "path");
5119 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01005120 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01005121
Christopher Fauleta2097962019-07-15 16:25:33 +02005122 /* Stores the query string. */
5123 lua_pushstring(L, "qs");
5124 if (*q == '?')
5125 q++;
5126 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005127 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02005128 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005129
Christopher Fauleta2097962019-07-15 16:25:33 +02005130 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
5131 struct htx_blk *blk = htx_get_blk(htx, pos);
5132 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005133
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005134 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02005135 break;
5136 if (type == HTX_BLK_DATA)
5137 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005138 }
Christopher Faulet2e47e3a2023-01-13 11:40:24 +01005139 if (htx->extra != HTX_UNKOWN_PAYLOAD_LENGTH)
Christopher Fauleta2097962019-07-15 16:25:33 +02005140 len += htx->extra;
5141
5142 /* Stores the request path. */
5143 lua_pushstring(L, "length");
5144 lua_pushinteger(L, len);
5145 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01005146
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005147 /* Create an empty array of HTTP request headers. */
5148 lua_pushstring(L, "response");
5149 lua_newtable(L);
5150 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01005151
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005152 /* Pop a class stream metatable and affect it to the table. */
5153 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
5154 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005155
5156 return 1;
5157}
5158
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005159__LJMP static int hlua_applet_http_set_var(lua_State *L)
5160{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005161 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005162 struct stream *s;
5163 const char *name;
5164 size_t len;
5165 struct sample smp;
5166
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005167 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
5168 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005169
5170 /* It is useles to retrieve the stream, but this function
5171 * runs only in a stream context.
5172 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005173 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005174 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02005175 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005176
5177 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01005178 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005179 hlua_lua2smp(L, 3, &smp);
5180
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02005181 /* Store the sample in a variable. We don't need to dup the smp, vars API
5182 * already takes care of duplicating dynamic var data.
5183 */
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005184 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005185
5186 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
5187 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
5188 else
5189 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
5190
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005191 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005192}
5193
5194__LJMP static int hlua_applet_http_unset_var(lua_State *L)
5195{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005196 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005197 struct stream *s;
5198 const char *name;
5199 size_t len;
5200 struct sample smp;
5201
5202 MAY_LJMP(check_args(L, 2, "unset_var"));
5203
5204 /* It is useles to retrieve the stream, but this function
5205 * runs only in a stream context.
5206 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005207 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005208 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02005209 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005210
5211 /* Unset the variable. */
5212 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005213 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
5214 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005215}
5216
5217__LJMP static int hlua_applet_http_get_var(lua_State *L)
5218{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005219 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005220 struct stream *s;
5221 const char *name;
5222 size_t len;
5223 struct sample smp;
5224
5225 MAY_LJMP(check_args(L, 2, "get_var"));
5226
5227 /* It is useles to retrieve the stream, but this function
5228 * runs only in a stream context.
5229 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005230 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005231 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02005232 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005233
5234 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02005235 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005236 lua_pushnil(L);
5237 return 1;
5238 }
5239
Aurelien DARRAGON41217722023-05-17 10:44:47 +02005240 return MAY_LJMP(hlua_smp2lua(L, &smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005241}
5242
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005243__LJMP static int hlua_applet_http_set_priv(lua_State *L)
5244{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005245 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5246 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005247 struct hlua *hlua;
5248
5249 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005250 if (!s->hlua)
5251 return 0;
5252 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005253
5254 MAY_LJMP(check_args(L, 2, "set_priv"));
5255
5256 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005257 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005258
5259 /* Get and store new value. */
5260 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5261 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5262
5263 return 0;
5264}
5265
5266__LJMP static int hlua_applet_http_get_priv(lua_State *L)
5267{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005268 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5269 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005270 struct hlua *hlua;
5271
5272 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005273 if (!s->hlua) {
5274 lua_pushnil(L);
5275 return 1;
5276 }
5277 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005278
5279 /* Push configuration index in the stack. */
5280 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5281
5282 return 1;
5283}
5284
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005285/* If expected data not yet available, it returns a yield. This function
5286 * consumes the data in the buffer. It returns a string containing the
5287 * data. This string can be empty.
5288 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005289__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005290{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005291 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005292 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005293 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005294 struct htx *htx;
5295 struct htx_blk *blk;
5296 size_t count;
5297 int stop = 0;
5298
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005299 htx = htx_from_buf(&req->buf);
5300 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02005301 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01005302
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005303 while (count && !stop && blk) {
5304 enum htx_blk_type type = htx_get_blk_type(blk);
5305 uint32_t sz = htx_get_blksz(blk);
5306 struct ist v;
5307 uint32_t vlen;
5308 char *nl;
5309
5310 vlen = sz;
5311 if (vlen > count) {
5312 if (type != HTX_BLK_DATA)
5313 break;
5314 vlen = count;
5315 }
5316
5317 switch (type) {
5318 case HTX_BLK_UNUSED:
5319 break;
5320
5321 case HTX_BLK_DATA:
5322 v = htx_get_blk_value(htx, blk);
5323 v.len = vlen;
5324 nl = istchr(v, '\n');
5325 if (nl != NULL) {
5326 stop = 1;
5327 vlen = nl - v.ptr + 1;
5328 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02005329 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005330 break;
5331
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005332 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005333 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005334 stop = 1;
5335 break;
5336
5337 default:
5338 break;
5339 }
5340
Willy Tarreau84240042022-02-28 16:51:23 +01005341 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005342 count -= vlen;
5343 if (sz == vlen)
5344 blk = htx_remove_blk(htx, blk);
5345 else {
5346 htx_cut_data_blk(htx, blk, vlen);
5347 break;
5348 }
5349 }
5350
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005351 /* The message was fully consumed and no more data are expected
5352 * (EOM flag set).
5353 */
Christopher Fauletc9e8a322023-06-12 09:16:27 +02005354 if (htx_is_empty(htx) && (sc_opposite(sc)->flags & SC_FL_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005355 stop = 1;
5356
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005357 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005358 if (!stop) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02005359 applet_need_more_data(luactx->appctx);
Christopher Fauleta2097962019-07-15 16:25:33 +02005360 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005361 }
5362
5363 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005364 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005365 return 1;
5366}
5367
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005368
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005369/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005370__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005371{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005372 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005373
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005374 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005375 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005376
Christopher Fauleta2097962019-07-15 16:25:33 +02005377 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005378}
5379
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005380/* If expected data not yet available, it returns a yield. This function
5381 * consumes the data in the buffer. It returns a string containing the
5382 * data. This string can be empty.
5383 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005384__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005385{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005386 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005387 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005388 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005389 struct htx *htx;
5390 struct htx_blk *blk;
5391 size_t count;
5392 int len;
5393
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005394 htx = htx_from_buf(&req->buf);
5395 len = MAY_LJMP(luaL_checkinteger(L, 2));
5396 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02005397 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005398 while (count && len && blk) {
5399 enum htx_blk_type type = htx_get_blk_type(blk);
5400 uint32_t sz = htx_get_blksz(blk);
5401 struct ist v;
5402 uint32_t vlen;
5403
5404 vlen = sz;
5405 if (len > 0 && vlen > len)
5406 vlen = len;
5407 if (vlen > count) {
5408 if (type != HTX_BLK_DATA)
5409 break;
5410 vlen = count;
5411 }
5412
5413 switch (type) {
5414 case HTX_BLK_UNUSED:
5415 break;
5416
5417 case HTX_BLK_DATA:
5418 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02005419 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005420 break;
5421
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005422 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005423 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005424 len = 0;
5425 break;
5426
5427 default:
5428 break;
5429 }
5430
Willy Tarreau84240042022-02-28 16:51:23 +01005431 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005432 count -= vlen;
5433 if (len > 0)
5434 len -= vlen;
5435 if (sz == vlen)
5436 blk = htx_remove_blk(htx, blk);
5437 else {
5438 htx_cut_data_blk(htx, blk, vlen);
5439 break;
5440 }
5441 }
5442
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005443 /* The message was fully consumed and no more data are expected
5444 * (EOM flag set).
5445 */
Christopher Fauletc9e8a322023-06-12 09:16:27 +02005446 if (htx_is_empty(htx) && (sc_opposite(sc)->flags & SC_FL_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005447 len = 0;
5448
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005449 htx_to_buf(htx, &req->buf);
5450
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005451 /* If we are no other data available, yield waiting for new data. */
5452 if (len) {
5453 if (len > 0) {
5454 lua_pushinteger(L, len);
5455 lua_replace(L, 2);
5456 }
Willy Tarreau90e8b452022-05-25 18:21:43 +02005457 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02005458 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005459 }
5460
5461 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005462 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005463 return 1;
5464}
5465
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005466/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005467__LJMP static int hlua_applet_http_recv(lua_State *L)
5468{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005469 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005470 int len = -1;
5471
5472 /* Check arguments. */
5473 if (lua_gettop(L) > 2)
5474 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
5475 if (lua_gettop(L) >= 2) {
5476 len = MAY_LJMP(luaL_checkinteger(L, 2));
5477 lua_pop(L, 1);
5478 }
5479
Christopher Fauleta2097962019-07-15 16:25:33 +02005480 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005481
Christopher Fauleta2097962019-07-15 16:25:33 +02005482 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005483 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005484
Christopher Fauleta2097962019-07-15 16:25:33 +02005485 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005486}
5487
5488/* Append data in the output side of the buffer. This data is immediately
5489 * sent. The function returns the amount of data written. If the buffer
5490 * cannot contain the data, the function yields. The function returns -1
5491 * if the channel is closed.
5492 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005493__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005494{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005495 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005496 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005497 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005498 struct htx *htx = htx_from_buf(&res->buf);
5499 const char *data;
5500 size_t len;
5501 int l = MAY_LJMP(luaL_checkinteger(L, 3));
5502 int max;
5503
Christopher Faulet9060fc02019-07-03 11:39:30 +02005504 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005505 if (!max)
5506 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005507
5508 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
5509
5510 /* Get the max amount of data which can write as input in the channel. */
5511 if (max > (len - l))
5512 max = len - l;
5513
5514 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02005515 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005516 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005517
5518 /* update counters. */
5519 l += max;
5520 lua_pop(L, 1);
5521 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005522
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005523 /* If some data is not send, declares the situation to the
5524 * applet, and returns a yield.
5525 */
5526 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005527 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005528 htx_to_buf(htx, &res->buf);
Christopher Faulet7b3d38a2023-05-05 11:28:45 +02005529 sc_need_room(sc, channel_recv_max(res) + 1);
Willy Tarreau9635e032018-10-16 17:52:55 +02005530 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005531 }
5532
Christopher Fauleta2097962019-07-15 16:25:33 +02005533 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005534 return 1;
5535}
5536
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005537/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005538 * yield the LUA process, and resume it without checking the
5539 * input arguments.
5540 */
5541__LJMP static int hlua_applet_http_send(lua_State *L)
5542{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005543 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005544 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005545
5546 /* We want to send some data. Headers must be sent. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005547 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005548 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
5549 WILL_LJMP(lua_error(L));
5550 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005551
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005552 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02005553 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005554
Christopher Fauleta2097962019-07-15 16:25:33 +02005555 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005556}
5557
5558__LJMP static int hlua_applet_http_addheader(lua_State *L)
5559{
5560 const char *name;
5561 int ret;
5562
5563 MAY_LJMP(hlua_checkapplet_http(L, 1));
5564 name = MAY_LJMP(luaL_checkstring(L, 2));
5565 MAY_LJMP(luaL_checkstring(L, 3));
5566
5567 /* Push in the stack the "response" entry. */
5568 ret = lua_getfield(L, 1, "response");
5569 if (ret != LUA_TTABLE) {
5570 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
5571 "is expected as an array. %s found", lua_typename(L, ret));
5572 WILL_LJMP(lua_error(L));
5573 }
5574
5575 /* check if the header is already registered if it is not
5576 * the case, register it.
5577 */
5578 ret = lua_getfield(L, -1, name);
5579 if (ret == LUA_TNIL) {
5580
5581 /* Entry not found. */
5582 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
5583
5584 /* Insert the new header name in the array in the top of the stack.
5585 * It left the new array in the top of the stack.
5586 */
5587 lua_newtable(L);
5588 lua_pushvalue(L, 2);
5589 lua_pushvalue(L, -2);
5590 lua_settable(L, -4);
5591
5592 } else if (ret != LUA_TTABLE) {
5593
5594 /* corruption error. */
5595 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
5596 "is expected as an array. %s found", name, lua_typename(L, ret));
5597 WILL_LJMP(lua_error(L));
5598 }
5599
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005600 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005601 * the header value as new entry.
5602 */
5603 lua_pushvalue(L, 3);
5604 ret = lua_rawlen(L, -2);
5605 lua_rawseti(L, -2, ret + 1);
5606 lua_pushboolean(L, 1);
5607 return 1;
5608}
5609
5610__LJMP static int hlua_applet_http_status(lua_State *L)
5611{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005612 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005613 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005614 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005615 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005616
5617 if (status < 100 || status > 599) {
5618 lua_pushboolean(L, 0);
5619 return 1;
5620 }
5621
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005622 http_ctx->status = status;
5623 http_ctx->reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005624 lua_pushboolean(L, 1);
5625 return 1;
5626}
5627
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005628
Christopher Fauleta2097962019-07-15 16:25:33 +02005629__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005630{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005631 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005632 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02005633 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005634 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005635 struct htx *htx;
5636 struct htx_sl *sl;
5637 struct h1m h1m;
5638 const char *status, *reason;
5639 const char *name, *value;
5640 size_t nlen, vlen;
5641 unsigned int flags;
5642
5643 /* Send the message at once. */
5644 htx = htx_from_buf(&res->buf);
5645 h1m_init_res(&h1m);
5646
5647 /* Use the same http version than the request. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005648 status = ultoa_r(http_ctx->status, trash.area, trash.size);
5649 reason = http_ctx->reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005650 if (reason == NULL)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005651 reason = http_get_reason(http_ctx->status);
5652 if (http_ctx->flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005653 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5654 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
5655 }
5656 else {
5657 flags = HTX_SL_F_IS_RESP;
5658 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
5659 }
5660 if (!sl) {
5661 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005662 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005663 WILL_LJMP(lua_error(L));
5664 }
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005665 sl->info.res.status = http_ctx->status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005666
5667 /* Get the array associated to the field "response" in the object AppletHTTP. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005668 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
5669 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005670 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005671 WILL_LJMP(lua_error(L));
5672 }
5673
5674 /* Browse the list of headers. */
5675 lua_pushnil(L);
5676 while(lua_next(L, -2) != 0) {
5677 /* We expect a string as -2. */
5678 if (lua_type(L, -2) != LUA_TSTRING) {
5679 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005680 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005681 lua_typename(L, lua_type(L, -2)));
5682 WILL_LJMP(lua_error(L));
5683 }
5684 name = lua_tolstring(L, -2, &nlen);
5685
5686 /* We expect an array as -1. */
5687 if (lua_type(L, -1) != LUA_TTABLE) {
5688 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 +02005689 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005690 name,
5691 lua_typename(L, lua_type(L, -1)));
5692 WILL_LJMP(lua_error(L));
5693 }
5694
5695 /* Browse the table who is on the top of the stack. */
5696 lua_pushnil(L);
5697 while(lua_next(L, -2) != 0) {
5698 int id;
5699
5700 /* We expect a number as -2. */
5701 if (lua_type(L, -2) != LUA_TNUMBER) {
5702 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 +02005703 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005704 name,
5705 lua_typename(L, lua_type(L, -2)));
5706 WILL_LJMP(lua_error(L));
5707 }
5708 id = lua_tointeger(L, -2);
5709
5710 /* We expect a string as -2. */
5711 if (lua_type(L, -1) != LUA_TSTRING) {
5712 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 +02005713 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005714 name, id,
5715 lua_typename(L, lua_type(L, -1)));
5716 WILL_LJMP(lua_error(L));
5717 }
5718 value = lua_tolstring(L, -1, &vlen);
5719
5720 /* Simple Protocol checks. */
Christopher Faulet545fbba2021-09-28 09:36:25 +02005721 if (isteqi(ist2(name, nlen), ist("transfer-encoding"))) {
5722 int ret;
5723
5724 ret = h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
5725 if (ret < 0) {
5726 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
5727 luactx->appctx->rule->arg.hlua_rule->fcn->name,
5728 name);
5729 WILL_LJMP(lua_error(L));
5730 }
5731 else if (ret == 0)
5732 goto next; /* Skip it */
5733 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005734 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
5735 struct ist v = ist2(value, vlen);
5736 int ret;
5737
5738 ret = h1_parse_cont_len_header(&h1m, &v);
5739 if (ret < 0) {
5740 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005741 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005742 name);
5743 WILL_LJMP(lua_error(L));
5744 }
5745 else if (ret == 0)
5746 goto next; /* Skip it */
5747 }
5748
5749 /* Add a new header */
5750 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
5751 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005752 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005753 name);
5754 WILL_LJMP(lua_error(L));
5755 }
5756 next:
5757 /* Remove the array from the stack, and get next element with a remaining string. */
5758 lua_pop(L, 1);
5759 }
5760
5761 /* Remove the array from the stack, and get next element with a remaining string. */
5762 lua_pop(L, 1);
5763 }
5764
5765 if (h1m.flags & H1_MF_CHNK)
5766 h1m.flags &= ~H1_MF_CLEN;
5767 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5768 h1m.flags |= H1_MF_XFER_LEN;
5769
5770 /* Uset HTX start-line flags */
5771 if (h1m.flags & H1_MF_XFER_ENC)
5772 flags |= HTX_SL_F_XFER_ENC;
5773 if (h1m.flags & H1_MF_XFER_LEN) {
5774 flags |= HTX_SL_F_XFER_LEN;
5775 if (h1m.flags & H1_MF_CHNK)
5776 flags |= HTX_SL_F_CHNK;
5777 else if (h1m.flags & H1_MF_CLEN)
5778 flags |= HTX_SL_F_CLEN;
5779 if (h1m.body_len == 0)
5780 flags |= HTX_SL_F_BODYLESS;
5781 }
5782 sl->flags |= flags;
5783
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005784 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005785 * and the status code implies the presence of a message body, we must
5786 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005787 * for the keepalive compliance. If the applet announces a transfer-encoding
5788 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005789 */
5790 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005791 http_ctx->status >= 200 && http_ctx->status != 204 && http_ctx->status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005792 /* Add a new header */
5793 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
5794 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
5795 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005796 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005797 WILL_LJMP(lua_error(L));
5798 }
5799 }
5800
5801 /* Finalize headers. */
5802 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
5803 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005804 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005805 WILL_LJMP(lua_error(L));
5806 }
5807
5808 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
5809 b_reset(&res->buf);
5810 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
5811 WILL_LJMP(lua_error(L));
5812 }
5813
5814 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005815 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005816
5817 /* Headers sent, set the flag. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005818 http_ctx->flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005819 return 0;
5820
5821}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005822/* We will build the status line and the headers of the HTTP response.
5823 * We will try send at once if its not possible, we give back the hand
5824 * waiting for more room.
5825 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005826__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005827{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005828 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005829 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005830 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005831
5832 if (co_data(res)) {
Christopher Faulet7b3d38a2023-05-05 11:28:45 +02005833 sc_need_room(sc, -1);
Christopher Fauleta2097962019-07-15 16:25:33 +02005834 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005835 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005836 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005837}
5838
5839
Christopher Fauleta2097962019-07-15 16:25:33 +02005840__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005841{
Christopher Fauleta2097962019-07-15 16:25:33 +02005842 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005843}
5844
Christopher Fauleta2097962019-07-15 16:25:33 +02005845/*
5846 *
5847 *
5848 * Class HTTP
5849 *
5850 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005851 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005852
5853/* Returns a struct hlua_txn if the stack entry "ud" is
5854 * a class stream, otherwise it throws an error.
5855 */
5856__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005857{
Christopher Fauleta2097962019-07-15 16:25:33 +02005858 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
5859}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005860
Christopher Fauleta2097962019-07-15 16:25:33 +02005861/* This function creates and push in the stack a HTTP object
5862 * according with a current TXN.
5863 */
5864static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
5865{
5866 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005867
Christopher Fauleta2097962019-07-15 16:25:33 +02005868 /* Check stack size. */
5869 if (!lua_checkstack(L, 3))
5870 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005871
Christopher Fauleta2097962019-07-15 16:25:33 +02005872 /* Create the object: obj[0] = userdata.
5873 * Note that the base of the Converters object is the
5874 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005875 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005876 lua_newtable(L);
5877 htxn = lua_newuserdata(L, sizeof(*htxn));
5878 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005879
5880 htxn->s = txn->s;
5881 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02005882 htxn->dir = txn->dir;
5883 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005884
5885 /* Pop a class stream metatable and affect it to the table. */
5886 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
5887 lua_setmetatable(L, -2);
5888
5889 return 1;
5890}
5891
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005892/* This function creates and returns an array containing the status-line
5893 * elements. This function does not fails.
5894 */
5895__LJMP static int hlua_http_get_stline(lua_State *L, struct htx_sl *sl)
5896{
5897 /* Create the table. */
5898 lua_newtable(L);
5899
5900 if (sl->flags & HTX_SL_F_IS_RESP) {
5901 lua_pushstring(L, "version");
5902 lua_pushlstring(L, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl));
5903 lua_settable(L, -3);
5904 lua_pushstring(L, "code");
5905 lua_pushlstring(L, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl));
5906 lua_settable(L, -3);
5907 lua_pushstring(L, "reason");
5908 lua_pushlstring(L, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl));
5909 lua_settable(L, -3);
5910 }
5911 else {
5912 lua_pushstring(L, "method");
5913 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
5914 lua_settable(L, -3);
5915 lua_pushstring(L, "uri");
5916 lua_pushlstring(L, HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl));
5917 lua_settable(L, -3);
5918 lua_pushstring(L, "version");
5919 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
5920 lua_settable(L, -3);
5921 }
5922 return 1;
5923}
5924
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005925/* This function creates ans returns an array of HTTP headers.
5926 * This function does not fails. It is used as wrapper with the
5927 * 2 following functions.
5928 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005929__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005930{
Christopher Fauleta2097962019-07-15 16:25:33 +02005931 struct htx *htx;
5932 int32_t pos;
5933
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005934 /* Create the table. */
5935 lua_newtable(L);
5936
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005937
Christopher Fauleta2097962019-07-15 16:25:33 +02005938 htx = htxbuf(&msg->chn->buf);
5939 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
5940 struct htx_blk *blk = htx_get_blk(htx, pos);
5941 enum htx_blk_type type = htx_get_blk_type(blk);
5942 struct ist n, v;
5943 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005944
Christopher Fauleta2097962019-07-15 16:25:33 +02005945 if (type == HTX_BLK_HDR) {
5946 n = htx_get_blk_name(htx,blk);
5947 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005948 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005949 else if (type == HTX_BLK_EOH)
5950 break;
5951 else
5952 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005953
Christopher Fauleta2097962019-07-15 16:25:33 +02005954 /* Check for existing entry:
5955 * assume that the table is on the top of the stack, and
5956 * push the key in the stack, the function lua_gettable()
5957 * perform the lookup.
5958 */
5959 lua_pushlstring(L, n.ptr, n.len);
5960 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005961
Christopher Fauleta2097962019-07-15 16:25:33 +02005962 switch (lua_type(L, -1)) {
5963 case LUA_TNIL:
5964 /* Table not found, create it. */
5965 lua_pop(L, 1); /* remove the nil value. */
5966 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
5967 lua_newtable(L); /* create and push empty table. */
5968 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5969 lua_rawseti(L, -2, 0); /* index header value (pop it). */
5970 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01005971 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005972
Christopher Fauleta2097962019-07-15 16:25:33 +02005973 case LUA_TTABLE:
5974 /* Entry found: push the value in the table. */
5975 len = lua_rawlen(L, -1);
5976 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5977 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
5978 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
5979 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005980
Christopher Fauleta2097962019-07-15 16:25:33 +02005981 default:
5982 /* Other cases are errors. */
5983 hlua_pusherror(L, "internal error during the parsing of headers.");
5984 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005985 }
5986 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005987 return 1;
5988}
5989
5990__LJMP static int hlua_http_req_get_headers(lua_State *L)
5991{
5992 struct hlua_txn *htxn;
5993
5994 MAY_LJMP(check_args(L, 1, "req_get_headers"));
5995 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5996
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005997 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005998 WILL_LJMP(lua_error(L));
5999
Christopher Faulet9d1332b2020-02-24 16:46:16 +01006000 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006001}
6002
6003__LJMP static int hlua_http_res_get_headers(lua_State *L)
6004{
6005 struct hlua_txn *htxn;
6006
6007 MAY_LJMP(check_args(L, 1, "res_get_headers"));
6008 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6009
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006010 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006011 WILL_LJMP(lua_error(L));
6012
Christopher Faulet9d1332b2020-02-24 16:46:16 +01006013 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006014}
6015
6016/* This function replace full header, or just a value in
6017 * the request or in the response. It is a wrapper fir the
6018 * 4 following functions.
6019 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01006020__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006021{
6022 size_t name_len;
6023 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6024 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
6025 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02006026 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02006027 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006028
Dragan Dosen26743032019-04-30 15:54:36 +02006029 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006030 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
6031
Christopher Fauleta2097962019-07-15 16:25:33 +02006032 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01006033 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02006034 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006035 return 0;
6036}
6037
6038__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
6039{
6040 struct hlua_txn *htxn;
6041
6042 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
6043 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6044
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006045 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006046 WILL_LJMP(lua_error(L));
6047
Christopher Fauletd1914aa2020-02-24 16:52:46 +01006048 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006049}
6050
6051__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
6052{
6053 struct hlua_txn *htxn;
6054
6055 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
6056 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6057
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006058 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006059 WILL_LJMP(lua_error(L));
6060
Christopher Fauletd1914aa2020-02-24 16:52:46 +01006061 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006062}
6063
6064__LJMP static int hlua_http_req_rep_val(lua_State *L)
6065{
6066 struct hlua_txn *htxn;
6067
6068 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
6069 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6070
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006071 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006072 WILL_LJMP(lua_error(L));
6073
Christopher Fauletd1914aa2020-02-24 16:52:46 +01006074 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02006075}
6076
6077__LJMP static int hlua_http_res_rep_val(lua_State *L)
6078{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006079 struct hlua_txn *htxn;
6080
6081 MAY_LJMP(check_args(L, 4, "res_rep_val"));
6082 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6083
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006084 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006085 WILL_LJMP(lua_error(L));
6086
Christopher Fauletd1914aa2020-02-24 16:52:46 +01006087 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006088}
6089
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006090/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006091 * It is a wrapper for the 2 following functions.
6092 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01006093__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006094{
6095 size_t len;
6096 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02006097 struct htx *htx = htxbuf(&msg->chn->buf);
6098 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006099
Christopher Fauleta2097962019-07-15 16:25:33 +02006100 ctx.blk = NULL;
6101 while (http_find_header(htx, ist2(name, len), &ctx, 1))
6102 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006103 return 0;
6104}
6105
6106__LJMP static int hlua_http_req_del_hdr(lua_State *L)
6107{
6108 struct hlua_txn *htxn;
6109
6110 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
6111 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6112
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006113 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006114 WILL_LJMP(lua_error(L));
6115
Christopher Fauletd31c7b32020-02-25 09:37:57 +01006116 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006117}
6118
6119__LJMP static int hlua_http_res_del_hdr(lua_State *L)
6120{
6121 struct hlua_txn *htxn;
6122
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006123 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006124 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6125
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006126 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006127 WILL_LJMP(lua_error(L));
6128
Christopher Fauletd31c7b32020-02-25 09:37:57 +01006129 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006130}
6131
6132/* This function adds an header. It is a wrapper used by
6133 * the 2 following functions.
6134 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01006135__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006136{
6137 size_t name_len;
6138 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6139 size_t value_len;
6140 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02006141 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006142
Christopher Fauleta2097962019-07-15 16:25:33 +02006143 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
6144 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006145 return 0;
6146}
6147
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006148__LJMP static int hlua_http_req_add_hdr(lua_State *L)
6149{
6150 struct hlua_txn *htxn;
6151
6152 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
6153 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6154
6155 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6156 WILL_LJMP(lua_error(L));
6157
6158 return hlua_http_add_hdr(L, &htxn->s->txn->req);
6159}
6160
6161__LJMP static int hlua_http_res_add_hdr(lua_State *L)
6162{
6163 struct hlua_txn *htxn;
6164
6165 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
6166 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6167
6168 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6169 WILL_LJMP(lua_error(L));
6170
6171 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
6172}
6173
6174static int hlua_http_req_set_hdr(lua_State *L)
6175{
6176 struct hlua_txn *htxn;
6177
6178 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
6179 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6180
6181 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6182 WILL_LJMP(lua_error(L));
6183
6184 hlua_http_del_hdr(L, &htxn->s->txn->req);
6185 return hlua_http_add_hdr(L, &htxn->s->txn->req);
6186}
6187
6188static int hlua_http_res_set_hdr(lua_State *L)
6189{
6190 struct hlua_txn *htxn;
6191
6192 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
6193 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6194
6195 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6196 WILL_LJMP(lua_error(L));
6197
6198 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
6199 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
6200}
6201
6202/* This function set the method. */
6203static int hlua_http_req_set_meth(lua_State *L)
6204{
6205 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6206 size_t name_len;
6207 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6208
6209 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6210 WILL_LJMP(lua_error(L));
6211
6212 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
6213 return 1;
6214}
6215
6216/* This function set the method. */
6217static int hlua_http_req_set_path(lua_State *L)
6218{
6219 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6220 size_t name_len;
6221 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6222
6223 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6224 WILL_LJMP(lua_error(L));
6225
6226 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
6227 return 1;
6228}
6229
6230/* This function set the query-string. */
6231static int hlua_http_req_set_query(lua_State *L)
6232{
6233 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6234 size_t name_len;
6235 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6236
6237 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6238 WILL_LJMP(lua_error(L));
6239
6240 /* Check length. */
6241 if (name_len > trash.size - 1) {
6242 lua_pushboolean(L, 0);
6243 return 1;
6244 }
6245
6246 /* Add the mark question as prefix. */
6247 chunk_reset(&trash);
6248 trash.area[trash.data++] = '?';
6249 memcpy(trash.area + trash.data, name, name_len);
6250 trash.data += name_len;
6251
6252 lua_pushboolean(L,
6253 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
6254 return 1;
6255}
6256
6257/* This function set the uri. */
6258static int hlua_http_req_set_uri(lua_State *L)
6259{
6260 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6261 size_t name_len;
6262 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6263
6264 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6265 WILL_LJMP(lua_error(L));
6266
6267 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
6268 return 1;
6269}
6270
6271/* This function set the response code & optionally reason. */
6272static int hlua_http_res_set_status(lua_State *L)
6273{
6274 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6275 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
6276 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6277 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
6278
6279 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6280 WILL_LJMP(lua_error(L));
6281
6282 http_res_set_status(code, reason, htxn->s);
6283 return 0;
6284}
6285
6286/*
6287 *
6288 *
6289 * Class HTTPMessage
6290 *
6291 *
6292 */
6293
6294/* Returns a struct http_msg if the stack entry "ud" is a class HTTPMessage,
6295 * otherwise it throws an error.
6296 */
6297__LJMP static struct http_msg *hlua_checkhttpmsg(lua_State *L, int ud)
6298{
6299 return MAY_LJMP(hlua_checkudata(L, ud, class_http_msg_ref));
6300}
6301
6302/* Creates and pushes on the stack a HTTP object according with a current TXN.
6303 */
Christopher Faulet78c35472020-02-26 17:14:08 +01006304static int hlua_http_msg_new(lua_State *L, struct http_msg *msg)
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006305{
6306 /* Check stack size. */
6307 if (!lua_checkstack(L, 3))
6308 return 0;
6309
6310 lua_newtable(L);
6311 lua_pushlightuserdata(L, msg);
6312 lua_rawseti(L, -2, 0);
6313
6314 /* Create the "channel" field that contains the request channel object. */
6315 lua_pushstring(L, "channel");
6316 if (!hlua_channel_new(L, msg->chn))
6317 return 0;
6318 lua_rawset(L, -3);
6319
6320 /* Pop a class stream metatable and affect it to the table. */
6321 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_msg_ref);
6322 lua_setmetatable(L, -2);
6323
6324 return 1;
6325}
6326
6327/* Helper function returning a filter attached to the HTTP message at the
6328 * position <ud> in the stack, filling the current offset and length of the
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006329 * filter. If no filter is attached, NULL is returned and <offset> and <len> are
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006330 * filled with output and input length respectively.
6331 */
6332static struct filter *hlua_http_msg_filter(lua_State *L, int ud, struct http_msg *msg, size_t *offset, size_t *len)
6333{
6334 struct channel *chn = msg->chn;
6335 struct htx *htx = htxbuf(&chn->buf);
6336 struct filter *filter = NULL;
6337
6338 *offset = co_data(msg->chn);
6339 *len = htx->data - co_data(msg->chn);
6340
6341 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
6342 filter = lua_touserdata (L, -1);
6343 if (msg->msg_state >= HTTP_MSG_DATA) {
6344 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6345
6346 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
6347 *len = flt_ctx->cur_len[CHN_IDX(chn)];
6348 }
6349 }
6350
6351 lua_pop(L, 1);
6352 return filter;
6353}
6354
6355/* Returns true if the channel attached to the HTTP message is the response
6356 * channel.
6357 */
6358__LJMP static int hlua_http_msg_is_resp(lua_State *L)
6359{
6360 struct http_msg *msg;
6361
6362 MAY_LJMP(check_args(L, 1, "is_resp"));
6363 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6364
6365 lua_pushboolean(L, !!(msg->chn->flags & CF_ISRESP));
6366 return 1;
6367}
6368
6369/* Returns an array containing the elements status-line of the HTTP message. It relies
6370 * on hlua_http_get_stline().
6371 */
6372__LJMP static int hlua_http_msg_get_stline(lua_State *L)
6373{
6374 struct http_msg *msg;
6375 struct htx *htx;
6376 struct htx_sl *sl;
6377
6378 MAY_LJMP(check_args(L, 1, "get_stline"));
6379 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6380
6381 if (msg->msg_state > HTTP_MSG_BODY)
6382 WILL_LJMP(lua_error(L));
6383
6384 htx = htxbuf(&msg->chn->buf);
6385 sl = http_get_stline(htx);
6386 if (!sl)
6387 return 0;
6388 return hlua_http_get_stline(L, sl);
6389}
6390
6391/* Returns an array containing all headers of the HTTP message. it relies on
6392 * hlua_http_get_headers().
6393 */
6394__LJMP static int hlua_http_msg_get_headers(lua_State *L)
6395{
6396 struct http_msg *msg;
6397
6398 MAY_LJMP(check_args(L, 1, "get_headers"));
6399 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6400
6401 if (msg->msg_state > HTTP_MSG_BODY)
6402 WILL_LJMP(lua_error(L));
6403
6404 return hlua_http_get_headers(L, msg);
6405}
6406
6407/* Deletes all occurrences of an header in the HTTP message matching on its
6408 * name. It relies on hlua_http_del_hdr().
6409 */
6410__LJMP static int hlua_http_msg_del_hdr(lua_State *L)
6411{
6412 struct http_msg *msg;
6413
6414 MAY_LJMP(check_args(L, 2, "del_header"));
6415 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6416
6417 if (msg->msg_state > HTTP_MSG_BODY)
6418 WILL_LJMP(lua_error(L));
6419
6420 return hlua_http_del_hdr(L, msg);
6421}
6422
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006423/* Matches the full value line of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006424 * message given its name against a regex and replaces it if it matches. It
6425 * relies on hlua_http_rep_hdr().
6426 */
6427__LJMP static int hlua_http_msg_rep_hdr(lua_State *L)
6428{
6429 struct http_msg *msg;
6430
6431 MAY_LJMP(check_args(L, 4, "rep_header"));
6432 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6433
6434 if (msg->msg_state > HTTP_MSG_BODY)
6435 WILL_LJMP(lua_error(L));
6436
6437 return hlua_http_rep_hdr(L, msg, 1);
6438}
6439
Ilya Shipitsinbd6b4be2021-10-15 16:18:21 +05006440/* Matches all comma-separated values of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006441 * message given its name against a regex and replaces it if it matches. It
6442 * relies on hlua_http_rep_hdr().
6443 */
6444__LJMP static int hlua_http_msg_rep_val(lua_State *L)
6445{
6446 struct http_msg *msg;
6447
6448 MAY_LJMP(check_args(L, 4, "rep_value"));
6449 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6450
6451 if (msg->msg_state > HTTP_MSG_BODY)
6452 WILL_LJMP(lua_error(L));
6453
6454 return hlua_http_rep_hdr(L, msg, 0);
6455}
6456
6457/* Add an header in the HTTP message. It relies on hlua_http_add_hdr() */
6458__LJMP static int hlua_http_msg_add_hdr(lua_State *L)
6459{
6460 struct http_msg *msg;
6461
6462 MAY_LJMP(check_args(L, 3, "add_header"));
6463 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6464
6465 if (msg->msg_state > HTTP_MSG_BODY)
6466 WILL_LJMP(lua_error(L));
6467
6468 return hlua_http_add_hdr(L, msg);
6469}
6470
6471/* Add an header in the HTTP message removing existing headers with the same
6472 * name. It relies on hlua_http_del_hdr() and hlua_http_add_hdr().
6473 */
6474__LJMP static int hlua_http_msg_set_hdr(lua_State *L)
6475{
6476 struct http_msg *msg;
6477
6478 MAY_LJMP(check_args(L, 3, "set_header"));
6479 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6480
6481 if (msg->msg_state > HTTP_MSG_BODY)
6482 WILL_LJMP(lua_error(L));
6483
6484 hlua_http_del_hdr(L, msg);
6485 return hlua_http_add_hdr(L, msg);
6486}
6487
6488/* Rewrites the request method. It relies on http_req_replace_stline(). */
6489__LJMP static int hlua_http_msg_set_meth(lua_State *L)
6490{
6491 struct stream *s;
6492 struct http_msg *msg;
6493 const char *name;
6494 size_t name_len;
6495
6496 MAY_LJMP(check_args(L, 2, "set_method"));
6497 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6498 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6499
6500 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6501 WILL_LJMP(lua_error(L));
6502
6503 s = chn_strm(msg->chn);
6504 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, s->be, s) != -1);
6505 return 1;
6506}
6507
6508/* Rewrites the request path. It relies on http_req_replace_stline(). */
6509__LJMP static int hlua_http_msg_set_path(lua_State *L)
6510{
6511 struct stream *s;
6512 struct http_msg *msg;
6513 const char *name;
6514 size_t name_len;
6515
6516 MAY_LJMP(check_args(L, 2, "set_path"));
6517 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6518 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6519
6520 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6521 WILL_LJMP(lua_error(L));
6522
6523 s = chn_strm(msg->chn);
6524 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, s->be, s) != -1);
6525 return 1;
6526}
6527
6528/* Rewrites the request query-string. It relies on http_req_replace_stline(). */
6529__LJMP static int hlua_http_msg_set_query(lua_State *L)
6530{
6531 struct stream *s;
6532 struct http_msg *msg;
6533 const char *name;
6534 size_t name_len;
6535
6536 MAY_LJMP(check_args(L, 2, "set_query"));
6537 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6538 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6539
6540 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6541 WILL_LJMP(lua_error(L));
6542
6543 /* Check length. */
6544 if (name_len > trash.size - 1) {
6545 lua_pushboolean(L, 0);
6546 return 1;
6547 }
6548
6549 /* Add the mark question as prefix. */
6550 chunk_reset(&trash);
6551 trash.area[trash.data++] = '?';
6552 memcpy(trash.area + trash.data, name, name_len);
6553 trash.data += name_len;
6554
6555 s = chn_strm(msg->chn);
6556 lua_pushboolean(L, http_req_replace_stline(2, trash.area, trash.data, s->be, s) != -1);
6557 return 1;
6558}
6559
6560/* Rewrites the request URI. It relies on http_req_replace_stline(). */
6561__LJMP static int hlua_http_msg_set_uri(lua_State *L)
6562{
6563 struct stream *s;
6564 struct http_msg *msg;
6565 const char *name;
6566 size_t name_len;
6567
6568 MAY_LJMP(check_args(L, 2, "set_uri"));
6569 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6570 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6571
6572 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6573 WILL_LJMP(lua_error(L));
6574
6575 s = chn_strm(msg->chn);
6576 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, s->be, s) != -1);
6577 return 1;
6578}
6579
6580/* Rewrites the response status code. It relies on http_res_set_status(). */
6581__LJMP static int hlua_http_msg_set_status(lua_State *L)
6582{
6583 struct http_msg *msg;
6584 unsigned int code;
6585 const char *reason;
6586 size_t reason_len;
6587
6588 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6589 code = MAY_LJMP(luaL_checkinteger(L, 2));
6590 reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, &reason_len));
6591
6592 if (!(msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6593 WILL_LJMP(lua_error(L));
6594
6595 lua_pushboolean(L, http_res_set_status(code, ist2(reason, reason_len), chn_strm(msg->chn)) != -1);
6596 return 1;
6597}
6598
6599/* Returns true if the HTTP message is full. */
6600__LJMP static int hlua_http_msg_is_full(lua_State *L)
6601{
6602 struct http_msg *msg;
6603
6604 MAY_LJMP(check_args(L, 1, "is_full"));
6605 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6606 lua_pushboolean(L, channel_full(msg->chn, 0));
6607 return 1;
6608}
6609
6610/* Returns true if the HTTP message may still receive data. */
6611__LJMP static int hlua_http_msg_may_recv(lua_State *L)
6612{
6613 struct http_msg *msg;
6614 struct htx *htx;
6615
6616 MAY_LJMP(check_args(L, 1, "may_recv"));
6617 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6618 htx = htxbuf(&msg->chn->buf);
6619 lua_pushboolean(L, (htx_expect_more(htx) && !channel_input_closed(msg->chn) && channel_may_recv(msg->chn)));
6620 return 1;
6621}
6622
6623/* Returns true if the HTTP message EOM was received */
6624__LJMP static int hlua_http_msg_is_eom(lua_State *L)
6625{
6626 struct http_msg *msg;
6627 struct htx *htx;
6628
6629 MAY_LJMP(check_args(L, 1, "may_recv"));
6630 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6631 htx = htxbuf(&msg->chn->buf);
6632 lua_pushboolean(L, !htx_expect_more(htx));
6633 return 1;
6634}
6635
6636/* Returns the number of bytes available in the input side of the HTTP
6637 * message. This function never fails.
6638 */
6639__LJMP static int hlua_http_msg_get_in_len(lua_State *L)
6640{
6641 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006642 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006643
6644 MAY_LJMP(check_args(L, 1, "input"));
6645 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006646 hlua_http_msg_filter(L, 1, msg, &output, &input);
6647 lua_pushinteger(L, input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006648 return 1;
6649}
6650
6651/* Returns the number of bytes available in the output side of the HTTP
6652 * message. This function never fails.
6653 */
6654__LJMP static int hlua_http_msg_get_out_len(lua_State *L)
6655{
6656 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006657 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006658
6659 MAY_LJMP(check_args(L, 1, "output"));
6660 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006661 hlua_http_msg_filter(L, 1, msg, &output, &input);
6662 lua_pushinteger(L, output);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006663 return 1;
6664}
6665
6666/* Copies at most <len> bytes of DATA blocks from the HTTP message <msg>
6667 * starting at the offset <offset> and put it in a string LUA variables. It
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006668 * returns the built string length. It stops on the first non-DATA HTX
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006669 * block. This function is called during the payload filtering, so the headers
6670 * are already scheduled for output (from the filter point of view).
6671 */
6672static int _hlua_http_msg_dup(struct http_msg *msg, lua_State *L, size_t offset, size_t len)
6673{
6674 struct htx *htx = htxbuf(&msg->chn->buf);
6675 struct htx_blk *blk;
6676 struct htx_ret htxret;
6677 luaL_Buffer b;
6678 int ret = 0;
6679
6680 luaL_buffinit(L, &b);
6681 htxret = htx_find_offset(htx, offset);
6682 for (blk = htxret.blk, offset = htxret.ret; blk && len; blk = htx_get_next_blk(htx, blk)) {
6683 enum htx_blk_type type = htx_get_blk_type(blk);
6684 struct ist v;
6685
6686 switch (type) {
6687 case HTX_BLK_UNUSED:
6688 break;
6689
6690 case HTX_BLK_DATA:
6691 v = htx_get_blk_value(htx, blk);
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006692 v = istadv(v, offset);
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006693 v = isttrim(v, len);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006694
6695 luaL_addlstring(&b, v.ptr, v.len);
6696 ret += v.len;
6697 break;
6698
6699 default:
vishnu0af4bd72021-10-24 06:46:24 +05306700 if (!ret)
6701 goto no_data;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006702 goto end;
6703 }
6704 offset = 0;
6705 }
6706
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006707end:
vishnu0af4bd72021-10-24 06:46:24 +05306708 if (!ret && (htx->flags & HTX_FL_EOM))
6709 goto no_data;
6710 luaL_pushresult(&b);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006711 return ret;
vishnu0af4bd72021-10-24 06:46:24 +05306712
6713 no_data:
6714 /* Remove the empty string and push nil on the stack */
6715 lua_pop(L, 1);
6716 lua_pushnil(L);
6717 return 0;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006718}
6719
6720/* Copies the string <str> to the HTTP message <msg> at the offset
6721 * <offset>. This function returns -1 if data cannot be copied. Otherwise, it
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006722 * returns the amount of data written. This function is responsible to update
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006723 * the filter context.
6724 */
6725static int _hlua_http_msg_insert(struct http_msg *msg, struct filter *filter, struct ist str, size_t offset)
6726{
6727 struct htx *htx = htx_from_buf(&msg->chn->buf);
6728 struct htx_ret htxret;
6729 int /*max, */ret = 0;
6730
6731 /* Nothing to do, just return */
6732 if (unlikely(istlen(str) == 0))
6733 goto end;
6734
6735 if (istlen(str) > htx_free_data_space(htx)) {
6736 ret = -1;
6737 goto end;
6738 }
6739
6740 htxret = htx_find_offset(htx, offset);
6741 if (!htxret.blk || htx_get_blk_type(htxret.blk) != HTX_BLK_DATA) {
6742 if (!htx_add_last_data(htx, str))
6743 goto end;
6744 }
6745 else {
6746 struct ist v = htx_get_blk_value(htx, htxret.blk);
6747 v.ptr += htxret.ret;
6748 v.len = 0;
6749 if (!htx_replace_blk_value(htx, htxret.blk, v, str))
6750 goto end;
6751 }
6752 ret = str.len;
6753 if (ret) {
6754 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6755 flt_update_offsets(filter, msg->chn, ret);
6756 flt_ctx->cur_len[CHN_IDX(msg->chn)] += ret;
6757 }
6758
6759 end:
6760 htx_to_buf(htx, &msg->chn->buf);
6761 return ret;
6762}
6763
6764/* Helper function removing at most <len> bytes of DATA blocks at the absolute
6765 * position <offset>. It stops on the first non-DATA HTX block. This function is
6766 * called during the payload filtering, so the headers are already scheduled for
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006767 * output (from the filter point of view). This function is responsible to
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006768 * update the filter context.
6769 */
6770static void _hlua_http_msg_delete(struct http_msg *msg, struct filter *filter, size_t offset, size_t len)
6771{
6772 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6773 struct htx *htx = htx_from_buf(&msg->chn->buf);
6774 struct htx_blk *blk;
6775 struct htx_ret htxret;
6776 size_t ret = 0;
6777
6778 /* Be sure <len> is always the amount of DATA to remove */
6779 if (htx->data == offset+len && htx_get_tail_type(htx) == HTX_BLK_DATA) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006780 /* When htx tail type == HTX_BLK_DATA, no need to take care
6781 * of special blocks like HTX_BLK_EOT.
6782 * We simply truncate after offset
6783 * (truncate targeted blk and discard the following ones)
6784 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006785 htx_truncate(htx, offset);
6786 ret = len;
6787 goto end;
6788 }
6789
6790 htxret = htx_find_offset(htx, offset);
6791 blk = htxret.blk;
6792 if (htxret.ret) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006793 /* dealing with offset: we need to trim targeted blk */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006794 struct ist v;
6795
6796 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
6797 goto end;
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006798
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006799 v = htx_get_blk_value(htx, blk);
Tim Duesterhusa029d782022-10-08 12:33:18 +02006800 v = istadv(v, htxret.ret);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006801
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006802 v = isttrim(v, len);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006803 /* trimming data in blk: discard everything after the offset
6804 * (replace 'v' with 'IST_NULL')
6805 */
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006806 blk = htx_replace_blk_value(htx, blk, v, IST_NULL);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006807 if (blk && v.len < len) {
6808 /* In this case, caller wants to keep removing data,
6809 * but we need to spare current blk
6810 * because it was already trimmed
6811 */
6812 blk = htx_get_next_blk(htx, blk);
6813 }
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006814 len -= v.len;
6815 ret += v.len;
6816 }
6817
6818
6819 while (blk && len) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006820 /* there is more data that needs to be discarded */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006821 enum htx_blk_type type = htx_get_blk_type(blk);
6822 uint32_t sz = htx_get_blksz(blk);
6823
6824 switch (type) {
6825 case HTX_BLK_UNUSED:
6826 break;
6827
6828 case HTX_BLK_DATA:
6829 if (len < sz) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006830 /* don't discard whole blk, only part of it
6831 * (from the beginning)
6832 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006833 htx_cut_data_blk(htx, blk, len);
6834 ret += len;
6835 goto end;
6836 }
6837 break;
6838
6839 default:
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006840 /* HTX_BLK_EOT blk won't be removed */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006841 goto end;
6842 }
6843
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006844 /* Remove all the data block */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006845 len -= sz;
6846 ret += sz;
6847 blk = htx_remove_blk(htx, blk);
6848 }
6849
6850end:
6851 flt_update_offsets(filter, msg->chn, -ret);
6852 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
6853 /* WARNING: we don't call htx_to_buf() on purpose, because we don't want
6854 * to loose the EOM flag if the message is empty.
6855 */
6856}
6857
6858/* Copies input data found in an HTTP message. Unlike the channel function used
6859 * to duplicate raw data, this one can only be called inside a filter, from
6860 * http_payload callback. So it cannot yield. An exception is returned if it is
6861 * called from another callback. If nothing was copied, a nil value is pushed on
6862 * the stack.
6863 */
6864__LJMP static int hlua_http_msg_get_body(lua_State *L)
6865{
6866 struct http_msg *msg;
6867 struct filter *filter;
6868 size_t output, input;
6869 int offset, len;
6870
6871 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
6872 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
6873 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6874
6875 if (msg->msg_state < HTTP_MSG_DATA)
6876 WILL_LJMP(lua_error(L));
6877
6878 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6879 if (!filter || !hlua_filter_from_payload(filter))
6880 WILL_LJMP(lua_error(L));
6881
6882 if (!ci_data(msg->chn) && channel_input_closed(msg->chn)) {
6883 lua_pushnil(L);
6884 return 1;
6885 }
6886
6887 offset = output;
6888 if (lua_gettop(L) > 1) {
6889 offset = MAY_LJMP(luaL_checkinteger(L, 2));
6890 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006891 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006892 offset += output;
6893 if (offset < output || offset > input + output) {
6894 lua_pushfstring(L, "offset out of range.");
6895 WILL_LJMP(lua_error(L));
6896 }
6897 }
6898 len = output + input - offset;
6899 if (lua_gettop(L) == 3) {
6900 len = MAY_LJMP(luaL_checkinteger(L, 3));
6901 if (!len)
6902 goto dup;
6903 if (len == -1)
6904 len = global.tune.bufsize;
6905 if (len < 0) {
6906 lua_pushfstring(L, "length out of range.");
6907 WILL_LJMP(lua_error(L));
6908 }
6909 }
6910
6911 dup:
6912 _hlua_http_msg_dup(msg, L, offset, len);
6913 return 1;
6914}
6915
6916/* Appends a string to the HTTP message, after all existing DATA blocks but
6917 * before the trailers, if any. It returns the amount of data written or -1 if
6918 * nothing was copied. Unlike the channel function used to append data, this one
6919 * can only be called inside a filter, from http_payload callback. So it cannot
6920 * yield. An exception is returned if it is called from another callback.
6921 */
6922__LJMP static int hlua_http_msg_append(lua_State *L)
6923{
6924 struct http_msg *msg;
6925 struct filter *filter;
6926 const char *str;
6927 size_t offset, len, sz;
6928 int ret;
6929
6930 MAY_LJMP(check_args(L, 2, "append"));
6931 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6932
6933 if (msg->msg_state < HTTP_MSG_DATA)
6934 WILL_LJMP(lua_error(L));
6935
6936 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6937 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6938 if (!filter || !hlua_filter_from_payload(filter))
6939 WILL_LJMP(lua_error(L));
6940
6941 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset+len);
6942 lua_pushinteger(L, ret);
6943 return 1;
6944}
6945
6946/* Prepends a string to the HTTP message, before all existing DATA blocks. It
6947 * returns the amount of data written or -1 if nothing was copied. Unlike the
6948 * channel function used to prepend data, this one can only be called inside a
6949 * filter, from http_payload callback. So it cannot yield. An exception is
6950 * returned if it is called from another callback.
6951 */
6952__LJMP static int hlua_http_msg_prepend(lua_State *L)
6953{
6954 struct http_msg *msg;
6955 struct filter *filter;
6956 const char *str;
6957 size_t offset, len, sz;
6958 int ret;
6959
6960 MAY_LJMP(check_args(L, 2, "prepend"));
6961 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006962
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006963 if (msg->msg_state < HTTP_MSG_DATA)
6964 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006965
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006966 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6967 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6968 if (!filter || !hlua_filter_from_payload(filter))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006969 WILL_LJMP(lua_error(L));
6970
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006971 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6972 lua_pushinteger(L, ret);
6973 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006974}
6975
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006976/* Inserts a string to the HTTP message at a given offset. By default the string
6977 * is appended at the end of DATA blocks. It returns the amount of data written
6978 * or -1 if nothing was copied. Unlike the channel function used to insert data,
6979 * this one can only be called inside a filter, from http_payload callback. So
6980 * it cannot yield. An exception is returned if it is called from another
6981 * callback.
6982 */
6983__LJMP static int hlua_http_msg_insert_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006984{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006985 struct http_msg *msg;
6986 struct filter *filter;
6987 const char *str;
6988 size_t input, output, sz;
6989 int offset;
6990 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006991
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006992 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
6993 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006994 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006995
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006996 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006997 WILL_LJMP(lua_error(L));
6998
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006999 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02007000 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007001 if (!filter || !hlua_filter_from_payload(filter))
7002 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007003
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02007004 offset = output;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007005 if (lua_gettop(L) > 2) {
7006 offset = MAY_LJMP(luaL_checkinteger(L, 3));
7007 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02007008 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007009 offset += output;
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02007010 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007011 lua_pushfstring(L, "offset out of range.");
7012 WILL_LJMP(lua_error(L));
7013 }
7014 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007015
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007016 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
7017 lua_pushinteger(L, ret);
7018 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007019}
7020
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007021/* Removes a given amount of data from the HTTP message at a given offset. By
7022 * default all DATA blocks are removed. It returns the amount of data
7023 * removed. Unlike the channel function used to remove data, this one can only
7024 * be called inside a filter, from http_payload callback. So it cannot yield. An
7025 * exception is returned if it is called from another callback.
7026 */
7027__LJMP static int hlua_http_msg_del_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007028{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007029 struct http_msg *msg;
7030 struct filter *filter;
7031 size_t input, output;
7032 int offset, len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007033
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007034 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
Boyang Lie0c54352022-05-10 17:47:23 +00007035 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007036 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007037
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007038 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007039 WILL_LJMP(lua_error(L));
7040
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02007041 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007042 if (!filter || !hlua_filter_from_payload(filter))
7043 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007044
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02007045 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00007046 if (lua_gettop(L) > 1) {
7047 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007048 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02007049 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007050 offset += output;
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02007051 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007052 lua_pushfstring(L, "offset out of range.");
7053 WILL_LJMP(lua_error(L));
7054 }
7055 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007056
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007057 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00007058 if (lua_gettop(L) == 3) {
7059 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007060 if (!len)
7061 goto end;
7062 if (len == -1)
7063 len = output + input - offset;
7064 if (len < 0 || offset + len > output + input) {
7065 lua_pushfstring(L, "length out of range.");
7066 WILL_LJMP(lua_error(L));
7067 }
7068 }
7069
7070 _hlua_http_msg_delete(msg, filter, offset, len);
7071
7072 end:
7073 lua_pushinteger(L, len);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007074 return 1;
7075}
7076
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05007077/* Replaces a given amount of data at the given offset by a string. By default,
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007078 * all remaining data are removed, accordingly to the filter context. It returns
7079 * the amount of data written or -1 if nothing was copied. Unlike the channel
7080 * function used to replace data, this one can only be called inside a filter,
7081 * from http_payload callback. So it cannot yield. An exception is returned if
7082 * it is called from another callback.
7083 */
7084__LJMP static int hlua_http_msg_set_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007085{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007086 struct http_msg *msg;
7087 struct filter *filter;
7088 struct htx *htx;
7089 const char *str;
7090 size_t input, output, sz;
7091 int offset, len;
7092 int ret;
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02007093
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007094 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
7095 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
7096 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7097
7098 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007099 WILL_LJMP(lua_error(L));
7100
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007101 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
7102 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
7103 if (!filter || !hlua_filter_from_payload(filter))
7104 WILL_LJMP(lua_error(L));
7105
7106 offset = output;
7107 if (lua_gettop(L) > 2) {
7108 offset = MAY_LJMP(luaL_checkinteger(L, 3));
7109 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02007110 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007111 offset += output;
7112 if (offset < output || offset > input + output) {
7113 lua_pushfstring(L, "offset out of range.");
7114 WILL_LJMP(lua_error(L));
7115 }
7116 }
7117
7118 len = output + input - offset;
7119 if (lua_gettop(L) == 4) {
7120 len = MAY_LJMP(luaL_checkinteger(L, 4));
7121 if (!len)
7122 goto set;
7123 if (len == -1)
7124 len = output + input - offset;
7125 if (len < 0 || offset + len > output + input) {
7126 lua_pushfstring(L, "length out of range.");
7127 WILL_LJMP(lua_error(L));
7128 }
7129 }
7130
7131 set:
7132 /* Be sure we can copied the string once input data will be removed. */
7133 htx = htx_from_buf(&msg->chn->buf);
7134 if (sz > htx_free_data_space(htx) + len)
7135 lua_pushinteger(L, -1);
7136 else {
7137 _hlua_http_msg_delete(msg, filter, offset, len);
7138 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
7139 lua_pushinteger(L, ret);
7140 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007141 return 1;
7142}
7143
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007144/* Prepends data into an HTTP message and forward it, from the filter point of
7145 * view. It returns the amount of data written or -1 if nothing was sent. Unlike
7146 * the channel function used to send data, this one can only be called inside a
7147 * filter, from http_payload callback. So it cannot yield. An exception is
7148 * returned if it is called from another callback.
7149 */
7150__LJMP static int hlua_http_msg_send(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007151{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007152 struct http_msg *msg;
7153 struct filter *filter;
7154 struct htx *htx;
7155 const char *str;
7156 size_t offset, len, sz;
7157 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007158
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007159 MAY_LJMP(check_args(L, 2, "send"));
7160 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7161
7162 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007163 WILL_LJMP(lua_error(L));
7164
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007165 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
7166 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
7167 if (!filter || !hlua_filter_from_payload(filter))
7168 WILL_LJMP(lua_error(L));
7169
7170 /* Return an error if the channel's output is closed */
7171 if (unlikely(channel_output_closed(msg->chn))) {
7172 lua_pushinteger(L, -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007173 return 1;
7174 }
7175
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007176 htx = htx_from_buf(&msg->chn->buf);
7177 if (sz > htx_free_data_space(htx)) {
7178 lua_pushinteger(L, -1);
7179 return 1;
7180 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007181
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007182 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
7183 if (ret > 0) {
7184 struct hlua_flt_ctx *flt_ctx = filter->ctx;
7185
7186 FLT_OFF(filter, msg->chn) += ret;
7187 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
7188 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
7189 }
7190
7191 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007192 return 1;
7193}
7194
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007195/* Forwards a given amount of bytes. It return -1 if the channel's output is
7196 * closed. Otherwise, it returns the number of bytes forwarded. Unlike the
7197 * channel function used to forward data, this one can only be called inside a
7198 * filter, from http_payload callback. So it cannot yield. An exception is
7199 * returned if it is called from another callback. All other functions deal with
7200 * DATA block, this one not.
7201*/
7202__LJMP static int hlua_http_msg_forward(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007203{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007204 struct http_msg *msg;
7205 struct filter *filter;
7206 size_t offset, len;
7207 int fwd, ret = 0;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007208
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007209 MAY_LJMP(check_args(L, 2, "forward"));
7210 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7211
7212 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007213 WILL_LJMP(lua_error(L));
7214
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007215 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
7216 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
7217 if (!filter || !hlua_filter_from_payload(filter))
7218 WILL_LJMP(lua_error(L));
7219
7220 /* Nothing to do, just return */
7221 if (!fwd)
7222 goto end;
7223
7224 /* Return an error if the channel's output is closed */
7225 if (unlikely(channel_output_closed(msg->chn))) {
7226 ret = -1;
7227 goto end;
7228 }
7229
7230 ret = fwd;
7231 if (ret > len)
7232 ret = len;
7233
7234 if (ret) {
7235 struct hlua_flt_ctx *flt_ctx = filter->ctx;
7236
7237 FLT_OFF(filter, msg->chn) += ret;
7238 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
7239 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
7240 }
7241
7242 end:
7243 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007244 return 1;
7245}
7246
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007247/* Set EOM flag on the HTX message.
7248 *
7249 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7250 * really know how to do without this feature.
7251 */
7252__LJMP static int hlua_http_msg_set_eom(lua_State *L)
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007253{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007254 struct http_msg *msg;
7255 struct htx *htx;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007256
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007257 MAY_LJMP(check_args(L, 1, "set_eom"));
7258 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7259 htx = htxbuf(&msg->chn->buf);
7260 htx->flags |= HTX_FL_EOM;
7261 return 0;
7262}
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007263
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007264/* Unset EOM flag on the HTX message.
7265 *
7266 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7267 * really know how to do without this feature.
7268 */
7269__LJMP static int hlua_http_msg_unset_eom(lua_State *L)
7270{
7271 struct http_msg *msg;
7272 struct htx *htx;
7273
7274 MAY_LJMP(check_args(L, 1, "set_eom"));
7275 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7276 htx = htxbuf(&msg->chn->buf);
7277 htx->flags &= ~HTX_FL_EOM;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007278 return 0;
7279}
7280
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007281/*
7282 *
7283 *
William Lallemand3956c4e2021-09-21 16:25:15 +02007284 * Class HTTPClient
7285 *
7286 *
7287 */
7288__LJMP static struct hlua_httpclient *hlua_checkhttpclient(lua_State *L, int ud)
7289{
7290 return MAY_LJMP(hlua_checkudata(L, ud, class_httpclient_ref));
7291}
7292
William Lallemandf77f1de2021-09-28 19:10:38 +02007293
7294/* stops the httpclient and ask it to kill itself */
7295__LJMP static int hlua_httpclient_gc(lua_State *L)
7296{
7297 struct hlua_httpclient *hlua_hc;
7298
7299 MAY_LJMP(check_args(L, 1, "__gc"));
7300
7301 hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
7302
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007303 if (MT_LIST_DELETE(&hlua_hc->by_hlua)) {
7304 /* we won the race against hlua_httpclient_destroy_all() */
William Lallemandbb581422022-10-20 10:57:28 +02007305 httpclient_stop_and_destroy(hlua_hc->hc);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007306 hlua_hc->hc = NULL;
7307 }
William Lallemandf77f1de2021-09-28 19:10:38 +02007308
7309 return 0;
7310}
7311
7312
William Lallemand3956c4e2021-09-21 16:25:15 +02007313__LJMP static int hlua_httpclient_new(lua_State *L)
7314{
7315 struct hlua_httpclient *hlua_hc;
7316 struct hlua *hlua;
7317
7318 /* Get hlua struct, or NULL if we execute from main lua state */
7319 hlua = hlua_gethlua(L);
7320 if (!hlua)
7321 return 0;
7322
7323 /* Check stack size. */
7324 if (!lua_checkstack(L, 3)) {
7325 hlua_pusherror(L, "httpclient: full stack");
7326 goto err;
7327 }
7328 /* Create the object: obj[0] = userdata. */
7329 lua_newtable(L);
7330 hlua_hc = MAY_LJMP(lua_newuserdata(L, sizeof(*hlua_hc)));
7331 lua_rawseti(L, -2, 0);
7332 memset(hlua_hc, 0, sizeof(*hlua_hc));
7333
7334 hlua_hc->hc = httpclient_new(hlua, 0, IST_NULL);
7335 if (!hlua_hc->hc)
7336 goto err;
7337
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007338 MT_LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
William Lallemandbb581422022-10-20 10:57:28 +02007339
William Lallemand3956c4e2021-09-21 16:25:15 +02007340 /* Pop a class stream metatable and affect it to the userdata. */
7341 lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
7342 lua_setmetatable(L, -2);
7343
7344 return 1;
7345
7346 err:
7347 WILL_LJMP(lua_error(L));
7348 return 0;
7349}
7350
7351
7352/*
7353 * Callback of the httpclient, this callback wakes the lua task up, once the
7354 * httpclient receives some data
7355 *
7356 */
7357
William Lallemandbd5739e2021-10-28 15:41:38 +02007358static void hlua_httpclient_cb(struct httpclient *hc)
William Lallemand3956c4e2021-09-21 16:25:15 +02007359{
7360 struct hlua *hlua = hc->caller;
7361
7362 if (!hlua || !hlua->task)
7363 return;
7364
7365 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7366}
7367
7368/*
William Lallemandd7df73a2021-09-23 17:54:00 +02007369 * Fill the lua stack with headers from the httpclient response
7370 * This works the same way as the hlua_http_get_headers() function
7371 */
7372__LJMP static int hlua_httpclient_get_headers(lua_State *L, struct hlua_httpclient *hlua_hc)
7373{
7374 struct http_hdr *hdr;
7375
7376 lua_newtable(L);
7377
William Lallemandef574b22021-10-05 16:19:31 +02007378 for (hdr = hlua_hc->hc->res.hdrs; hdr && isttest(hdr->n); hdr++) {
William Lallemandd7df73a2021-09-23 17:54:00 +02007379 struct ist n, v;
7380 int len;
7381
7382 n = hdr->n;
7383 v = hdr->v;
7384
7385 /* Check for existing entry:
7386 * assume that the table is on the top of the stack, and
7387 * push the key in the stack, the function lua_gettable()
7388 * perform the lookup.
7389 */
7390
7391 lua_pushlstring(L, n.ptr, n.len);
7392 lua_gettable(L, -2);
7393
7394 switch (lua_type(L, -1)) {
7395 case LUA_TNIL:
7396 /* Table not found, create it. */
7397 lua_pop(L, 1); /* remove the nil value. */
7398 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
7399 lua_newtable(L); /* create and push empty table. */
7400 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7401 lua_rawseti(L, -2, 0); /* index header value (pop it). */
7402 lua_rawset(L, -3); /* index new table with header name (pop the values). */
7403 break;
7404
7405 case LUA_TTABLE:
7406 /* Entry found: push the value in the table. */
7407 len = lua_rawlen(L, -1);
7408 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7409 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
7410 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
7411 break;
7412
7413 default:
7414 /* Other cases are errors. */
7415 hlua_pusherror(L, "internal error during the parsing of headers.");
7416 WILL_LJMP(lua_error(L));
7417 }
7418 }
7419 return 1;
7420}
7421
7422/*
William Lallemand746e6f32021-10-06 10:57:44 +02007423 * Allocate and return an array of http_hdr ist extracted from the <headers> lua table
7424 *
7425 * Caller must free the result
7426 */
7427struct http_hdr *hlua_httpclient_table_to_hdrs(lua_State *L)
7428{
7429 struct http_hdr hdrs[global.tune.max_http_hdr];
7430 struct http_hdr *result = NULL;
7431 uint32_t hdr_num = 0;
7432
7433 lua_pushnil(L);
7434 while (lua_next(L, -2) != 0) {
7435 struct ist name, value;
7436 const char *n, *v;
7437 size_t nlen, vlen;
7438
7439 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
7440 /* Skip element if the key is not a string or if the value is not a table */
7441 goto next_hdr;
7442 }
7443
7444 n = lua_tolstring(L, -2, &nlen);
7445 name = ist2(n, nlen);
7446
7447 /* Loop on header's values */
7448 lua_pushnil(L);
7449 while (lua_next(L, -2)) {
7450 if (!lua_isstring(L, -1)) {
7451 /* Skip the value if it is not a string */
7452 goto next_value;
7453 }
7454
7455 v = lua_tolstring(L, -1, &vlen);
7456 value = ist2(v, vlen);
7457 name = ist2(n, nlen);
7458
7459 hdrs[hdr_num].n = istdup(name);
7460 hdrs[hdr_num].v = istdup(value);
7461
7462 hdr_num++;
7463
7464 next_value:
7465 lua_pop(L, 1);
7466 }
7467
7468 next_hdr:
7469 lua_pop(L, 1);
7470
7471 }
7472
7473 if (hdr_num) {
7474 /* alloc and copy the headers in the httpclient struct */
Tim Duesterhus16cc16d2021-11-06 15:14:45 +01007475 result = calloc((hdr_num + 1), sizeof(*result));
William Lallemand746e6f32021-10-06 10:57:44 +02007476 if (!result)
7477 goto skip_headers;
7478 memcpy(result, hdrs, sizeof(struct http_hdr) * (hdr_num + 1));
7479
7480 result[hdr_num].n = IST_NULL;
7481 result[hdr_num].v = IST_NULL;
7482 }
7483
7484skip_headers:
William Lallemand746e6f32021-10-06 10:57:44 +02007485
7486 return result;
7487}
7488
7489
William Lallemandbd5739e2021-10-28 15:41:38 +02007490/*
7491 * For each yield, checks if there is some data in the httpclient and push them
7492 * in the lua buffer, once the httpclient finished its job, push the result on
7493 * the stack
7494 */
7495__LJMP static int hlua_httpclient_rcv_yield(lua_State *L, int status, lua_KContext ctx)
7496{
7497 struct buffer *tr;
7498 int res;
7499 struct hlua *hlua = hlua_gethlua(L);
7500 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7501
7502
7503 tr = get_trash_chunk();
7504
7505 res = httpclient_res_xfer(hlua_hc->hc, tr);
7506 luaL_addlstring(&hlua_hc->b, b_orig(tr), res);
7507
7508 if (!httpclient_data(hlua_hc->hc) && httpclient_ended(hlua_hc->hc)) {
7509
7510 luaL_pushresult(&hlua_hc->b);
7511 lua_settable(L, -3);
7512
7513 lua_pushstring(L, "status");
7514 lua_pushinteger(L, hlua_hc->hc->res.status);
7515 lua_settable(L, -3);
7516
7517
7518 lua_pushstring(L, "reason");
7519 lua_pushlstring(L, hlua_hc->hc->res.reason.ptr, hlua_hc->hc->res.reason.len);
7520 lua_settable(L, -3);
7521
7522 lua_pushstring(L, "headers");
7523 hlua_httpclient_get_headers(L, hlua_hc);
7524 lua_settable(L, -3);
7525
7526 return 1;
7527 }
7528
7529 if (httpclient_data(hlua_hc->hc))
7530 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7531
7532 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7533
7534 return 0;
7535}
7536
7537/*
7538 * Call this when trying to stream a body during a request
7539 */
7540__LJMP static int hlua_httpclient_snd_yield(lua_State *L, int status, lua_KContext ctx)
7541{
7542 struct hlua *hlua;
7543 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7544 const char *body_str = NULL;
7545 int ret;
7546 int end = 0;
7547 size_t buf_len;
7548 size_t to_send = 0;
7549
7550 hlua = hlua_gethlua(L);
7551
7552 if (!hlua || !hlua->task)
7553 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7554 "'frontend', 'backend' or 'task'"));
7555
7556 ret = lua_getfield(L, -1, "body");
7557 if (ret != LUA_TSTRING)
7558 goto rcv;
7559
7560 body_str = lua_tolstring(L, -1, &buf_len);
7561 lua_pop(L, 1);
7562
Christopher Fauletfc591292022-01-12 14:46:03 +01007563 to_send = buf_len - hlua_hc->sent;
William Lallemandbd5739e2021-10-28 15:41:38 +02007564
7565 if ((hlua_hc->sent + to_send) >= buf_len)
7566 end = 1;
7567
7568 /* the end flag is always set since we are using the whole remaining size */
7569 hlua_hc->sent += httpclient_req_xfer(hlua_hc->hc, ist2(body_str + hlua_hc->sent, to_send), end);
7570
7571 if (buf_len > hlua_hc->sent) {
7572 /* still need to process the buffer */
7573 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
7574 } else {
7575 goto rcv;
7576 /* we sent the whole request buffer we can recv */
7577 }
7578 return 0;
7579
7580rcv:
7581
7582 /* we return a "res" object */
7583 lua_newtable(L);
7584
William Lallemandbd5739e2021-10-28 15:41:38 +02007585 lua_pushstring(L, "body");
William Lallemandd1187eb2021-11-02 10:40:06 +01007586 luaL_buffinit(L, &hlua_hc->b);
William Lallemandbd5739e2021-10-28 15:41:38 +02007587
William Lallemand933fe392021-11-04 09:45:58 +01007588 task_wakeup(hlua->task, TASK_WOKEN_MSG);
William Lallemandbd5739e2021-10-28 15:41:38 +02007589 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7590
7591 return 1;
7592}
William Lallemand746e6f32021-10-06 10:57:44 +02007593
William Lallemand3956c4e2021-09-21 16:25:15 +02007594/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007595 * Send an HTTP request and wait for a response
William Lallemand3956c4e2021-09-21 16:25:15 +02007596 */
7597
William Lallemanddc2cc902021-10-26 11:43:26 +02007598__LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
William Lallemand3956c4e2021-09-21 16:25:15 +02007599{
7600 struct hlua_httpclient *hlua_hc;
William Lallemand746e6f32021-10-06 10:57:44 +02007601 struct http_hdr *hdrs = NULL;
7602 struct http_hdr *hdrs_i = NULL;
William Lallemand3956c4e2021-09-21 16:25:15 +02007603 struct hlua *hlua;
William Lallemand746e6f32021-10-06 10:57:44 +02007604 const char *url_str = NULL;
William Lallemanddec25c32021-10-25 19:48:37 +02007605 const char *body_str = NULL;
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007606 size_t buf_len = 0;
William Lallemand746e6f32021-10-06 10:57:44 +02007607 int ret;
William Lallemand3956c4e2021-09-21 16:25:15 +02007608
7609 hlua = hlua_gethlua(L);
7610
7611 if (!hlua || !hlua->task)
7612 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7613 "'frontend', 'backend' or 'task'"));
7614
William Lallemand746e6f32021-10-06 10:57:44 +02007615 if (lua_gettop(L) != 2 || lua_type(L, -1) != LUA_TTABLE)
7616 WILL_LJMP(luaL_error(L, "'get' needs a table as argument"));
7617
William Lallemand4f4f2b72022-02-17 20:00:23 +01007618 hlua_hc = hlua_checkhttpclient(L, 1);
7619
William Lallemand7177a952022-03-03 15:33:12 +01007620 lua_pushnil(L); /* first key */
7621 while (lua_next(L, 2)) {
7622 if (strcmp(lua_tostring(L, -2), "dst") == 0) {
7623 if (httpclient_set_dst(hlua_hc->hc, lua_tostring(L, -1)) < 0)
7624 WILL_LJMP(luaL_error(L, "Can't use the 'dst' argument"));
William Lallemand4f4f2b72022-02-17 20:00:23 +01007625
William Lallemand7177a952022-03-03 15:33:12 +01007626 } else if (strcmp(lua_tostring(L, -2), "url") == 0) {
7627 if (lua_type(L, -1) != LUA_TSTRING)
7628 WILL_LJMP(luaL_error(L, "invalid parameter in 'url', must be a string"));
7629 url_str = lua_tostring(L, -1);
William Lallemand3956c4e2021-09-21 16:25:15 +02007630
William Lallemand7177a952022-03-03 15:33:12 +01007631 } else if (strcmp(lua_tostring(L, -2), "timeout") == 0) {
7632 if (lua_type(L, -1) != LUA_TNUMBER)
7633 WILL_LJMP(luaL_error(L, "invalid parameter in 'timeout', must be a number"));
7634 httpclient_set_timeout(hlua_hc->hc, lua_tointeger(L, -1));
William Lallemandb4a4ef62022-02-23 14:18:16 +01007635
William Lallemand7177a952022-03-03 15:33:12 +01007636 } else if (strcmp(lua_tostring(L, -2), "headers") == 0) {
7637 if (lua_type(L, -1) != LUA_TTABLE)
7638 WILL_LJMP(luaL_error(L, "invalid parameter in 'headers', must be a table"));
7639 hdrs = hlua_httpclient_table_to_hdrs(L);
William Lallemand79416cb2021-09-24 14:51:44 +02007640
William Lallemand7177a952022-03-03 15:33:12 +01007641 } else if (strcmp(lua_tostring(L, -2), "body") == 0) {
7642 if (lua_type(L, -1) != LUA_TSTRING)
7643 WILL_LJMP(luaL_error(L, "invalid parameter in 'body', must be a string"));
7644 body_str = lua_tolstring(L, -1, &buf_len);
William Lallemandbd5739e2021-10-28 15:41:38 +02007645
William Lallemand7177a952022-03-03 15:33:12 +01007646 } else {
7647 WILL_LJMP(luaL_error(L, "'%s' invalid parameter name", lua_tostring(L, -2)));
7648 }
7649 /* removes 'value'; keeps 'key' for next iteration */
7650 lua_pop(L, 1);
7651 }
William Lallemanddec25c32021-10-25 19:48:37 +02007652
William Lallemand746e6f32021-10-06 10:57:44 +02007653 if (!url_str) {
7654 WILL_LJMP(luaL_error(L, "'get' need a 'url' argument"));
7655 return 0;
7656 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007657
William Lallemand10a37362022-03-02 16:18:26 +01007658 hlua_hc->sent = 0;
William Lallemand3956c4e2021-09-21 16:25:15 +02007659
Aurelien DARRAGON03564072023-02-09 15:26:25 +01007660 istfree(&hlua_hc->hc->req.url);
William Lallemand3956c4e2021-09-21 16:25:15 +02007661 hlua_hc->hc->req.url = istdup(ist(url_str));
William Lallemanddc2cc902021-10-26 11:43:26 +02007662 hlua_hc->hc->req.meth = meth;
William Lallemand3956c4e2021-09-21 16:25:15 +02007663
7664 /* update the httpclient callbacks */
William Lallemandbd5739e2021-10-28 15:41:38 +02007665 hlua_hc->hc->ops.res_stline = hlua_httpclient_cb;
7666 hlua_hc->hc->ops.res_headers = hlua_httpclient_cb;
7667 hlua_hc->hc->ops.res_payload = hlua_httpclient_cb;
William Lallemand8f170c72022-03-15 10:52:07 +01007668 hlua_hc->hc->ops.res_end = hlua_httpclient_cb;
William Lallemand3956c4e2021-09-21 16:25:15 +02007669
William Lallemandbd5739e2021-10-28 15:41:38 +02007670 /* a body is available, it will use the request callback */
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007671 if (body_str && buf_len) {
William Lallemandbd5739e2021-10-28 15:41:38 +02007672 hlua_hc->hc->ops.req_payload = hlua_httpclient_cb;
7673 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007674
William Lallemandbd5739e2021-10-28 15:41:38 +02007675 ret = httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, meth, hdrs, IST_NULL);
William Lallemand3956c4e2021-09-21 16:25:15 +02007676
William Lallemand746e6f32021-10-06 10:57:44 +02007677 /* free the temporary headers array */
7678 hdrs_i = hdrs;
7679 while (hdrs_i && isttest(hdrs_i->n)) {
7680 istfree(&hdrs_i->n);
7681 istfree(&hdrs_i->v);
7682 hdrs_i++;
7683 }
7684 ha_free(&hdrs);
7685
7686
William Lallemand6137a9e2021-10-26 15:01:53 +02007687 if (ret != ERR_NONE) {
7688 WILL_LJMP(luaL_error(L, "Can't generate the HTTP request"));
7689 return 0;
7690 }
7691
William Lallemandc2d3db42022-04-26 11:46:13 +02007692 if (!httpclient_start(hlua_hc->hc))
7693 WILL_LJMP(luaL_error(L, "couldn't start the httpclient"));
William Lallemand6137a9e2021-10-26 15:01:53 +02007694
William Lallemandbd5739e2021-10-28 15:41:38 +02007695 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
William Lallemand3956c4e2021-09-21 16:25:15 +02007696
William Lallemand3956c4e2021-09-21 16:25:15 +02007697 return 0;
7698}
7699
7700/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007701 * Sends an HTTP HEAD request and wait for a response
7702 *
7703 * httpclient:head(url, headers, payload)
7704 */
7705__LJMP static int hlua_httpclient_head(lua_State *L)
7706{
7707 return hlua_httpclient_send(L, HTTP_METH_HEAD);
7708}
7709
7710/*
7711 * Send an HTTP GET request and wait for a response
7712 *
7713 * httpclient:get(url, headers, payload)
7714 */
7715__LJMP static int hlua_httpclient_get(lua_State *L)
7716{
7717 return hlua_httpclient_send(L, HTTP_METH_GET);
7718
7719}
7720
7721/*
7722 * Sends an HTTP PUT request and wait for a response
7723 *
7724 * httpclient:put(url, headers, payload)
7725 */
7726__LJMP static int hlua_httpclient_put(lua_State *L)
7727{
7728 return hlua_httpclient_send(L, HTTP_METH_PUT);
7729}
7730
7731/*
7732 * Send an HTTP POST request and wait for a response
7733 *
7734 * httpclient:post(url, headers, payload)
7735 */
7736__LJMP static int hlua_httpclient_post(lua_State *L)
7737{
7738 return hlua_httpclient_send(L, HTTP_METH_POST);
7739}
7740
7741
7742/*
7743 * Sends an HTTP DELETE request and wait for a response
7744 *
7745 * httpclient:delete(url, headers, payload)
7746 */
7747__LJMP static int hlua_httpclient_delete(lua_State *L)
7748{
7749 return hlua_httpclient_send(L, HTTP_METH_DELETE);
7750}
7751
7752/*
William Lallemand3956c4e2021-09-21 16:25:15 +02007753 *
7754 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007755 * Class TXN
7756 *
7757 *
7758 */
7759
7760/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02007761 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007762 */
7763__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
7764{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007765 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007766}
7767
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007768__LJMP static int hlua_set_var(lua_State *L)
7769{
7770 struct hlua_txn *htxn;
7771 const char *name;
7772 size_t len;
7773 struct sample smp;
7774
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007775 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7776 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007777
7778 /* It is useles to retrieve the stream, but this function
7779 * runs only in a stream context.
7780 */
7781 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7782 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7783
7784 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01007785 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007786 hlua_lua2smp(L, 3, &smp);
7787
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02007788 /* Store the sample in a variable. We don't need to dup the smp, vars API
7789 * already takes care of duplicating dynamic var data.
7790 */
Willy Tarreau7560dd42016-03-10 16:28:58 +01007791 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007792
7793 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
7794 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
7795 else
7796 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
7797
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007798 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007799}
7800
Christopher Faulet85d79c92016-11-09 16:54:56 +01007801__LJMP static int hlua_unset_var(lua_State *L)
7802{
7803 struct hlua_txn *htxn;
7804 const char *name;
7805 size_t len;
7806 struct sample smp;
7807
7808 MAY_LJMP(check_args(L, 2, "unset_var"));
7809
7810 /* It is useles to retrieve the stream, but this function
7811 * runs only in a stream context.
7812 */
7813 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7814 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7815
7816 /* Unset the variable. */
7817 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007818 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
7819 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01007820}
7821
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007822__LJMP static int hlua_get_var(lua_State *L)
7823{
7824 struct hlua_txn *htxn;
7825 const char *name;
7826 size_t len;
7827 struct sample smp;
7828
7829 MAY_LJMP(check_args(L, 2, "get_var"));
7830
7831 /* It is useles to retrieve the stream, but this function
7832 * runs only in a stream context.
7833 */
7834 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7835 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7836
Willy Tarreau7560dd42016-03-10 16:28:58 +01007837 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02007838 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007839 lua_pushnil(L);
7840 return 1;
7841 }
7842
Aurelien DARRAGON41217722023-05-17 10:44:47 +02007843 return MAY_LJMP(hlua_smp2lua(L, &smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007844}
7845
Willy Tarreau59551662015-03-10 14:23:13 +01007846__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007847{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007848 struct hlua *hlua;
7849
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007850 MAY_LJMP(check_args(L, 2, "set_priv"));
7851
Willy Tarreau87b09662015-04-03 00:22:06 +02007852 /* It is useles to retrieve the stream, but this function
7853 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007854 */
7855 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007856
7857 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007858 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007859 if (!hlua)
7860 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007861
7862 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02007863 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007864
7865 /* Get and store new value. */
7866 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
7867 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
7868
7869 return 0;
7870}
7871
Willy Tarreau59551662015-03-10 14:23:13 +01007872__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007873{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007874 struct hlua *hlua;
7875
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007876 MAY_LJMP(check_args(L, 1, "get_priv"));
7877
Willy Tarreau87b09662015-04-03 00:22:06 +02007878 /* It is useles to retrieve the stream, but this function
7879 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007880 */
7881 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007882
7883 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007884 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007885 if (!hlua) {
7886 lua_pushnil(L);
7887 return 1;
7888 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007889
7890 /* Push configuration index in the stack. */
7891 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
7892
7893 return 1;
7894}
7895
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007896/* Create stack entry containing a class TXN. This function
7897 * return 0 if the stack does not contains free slots,
7898 * otherwise it returns 1.
7899 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007900static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007901{
Willy Tarreaude491382015-04-06 11:04:28 +02007902 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007903
7904 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007905 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007906 return 0;
7907
7908 /* NOTE: The allocation never fails. The failure
7909 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007910 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007911 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007912 /* Create the object: obj[0] = userdata. */
7913 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02007914 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007915 lua_rawseti(L, -2, 0);
7916
Willy Tarreaude491382015-04-06 11:04:28 +02007917 htxn->s = s;
7918 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01007919 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007920 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007921
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007922 /* Create the "f" field that contains a list of fetches. */
7923 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007924 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007925 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007926 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007927
7928 /* Create the "sf" field that contains a list of stringsafe fetches. */
7929 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007930 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007931 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007932 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007933
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007934 /* Create the "c" field that contains a list of converters. */
7935 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02007936 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007937 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007938 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007939
7940 /* Create the "sc" field that contains a list of stringsafe converters. */
7941 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01007942 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007943 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007944 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007945
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007946 /* Create the "req" field that contains the request channel object. */
7947 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007948 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007949 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007950 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007951
7952 /* Create the "res" field that contains the response channel object. */
7953 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007954 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007955 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007956 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007957
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007958 /* Creates the HTTP object is the current proxy allows http. */
7959 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01007960 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02007961 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007962 return 0;
7963 }
7964 else
7965 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007966 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007967
Christopher Faulet78c35472020-02-26 17:14:08 +01007968 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX) {
7969 /* HTTPMessage object are created when a lua TXN is created from
7970 * a filter context only
7971 */
7972
7973 /* Creates the HTTP-Request object is the current proxy allows http. */
7974 lua_pushstring(L, "http_req");
7975 if (p->mode == PR_MODE_HTTP) {
7976 if (!hlua_http_msg_new(L, &s->txn->req))
7977 return 0;
7978 }
7979 else
7980 lua_pushnil(L);
7981 lua_rawset(L, -3);
7982
7983 /* Creates the HTTP-Response object is the current proxy allows http. */
7984 lua_pushstring(L, "http_res");
7985 if (p->mode == PR_MODE_HTTP) {
7986 if (!hlua_http_msg_new(L, &s->txn->rsp))
7987 return 0;
7988 }
7989 else
7990 lua_pushnil(L);
7991 lua_rawset(L, -3);
7992 }
7993
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007994 /* Pop a class sesison metatable and affect it to the userdata. */
7995 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
7996 lua_setmetatable(L, -2);
7997
7998 return 1;
7999}
8000
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008001__LJMP static int hlua_txn_deflog(lua_State *L)
8002{
8003 const char *msg;
8004 struct hlua_txn *htxn;
8005
8006 MAY_LJMP(check_args(L, 2, "deflog"));
8007 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8008 msg = MAY_LJMP(luaL_checkstring(L, 2));
8009
8010 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
8011 return 0;
8012}
8013
8014__LJMP static int hlua_txn_log(lua_State *L)
8015{
8016 int level;
8017 const char *msg;
8018 struct hlua_txn *htxn;
8019
8020 MAY_LJMP(check_args(L, 3, "log"));
8021 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8022 level = MAY_LJMP(luaL_checkinteger(L, 2));
8023 msg = MAY_LJMP(luaL_checkstring(L, 3));
8024
8025 if (level < 0 || level >= NB_LOG_LEVELS)
8026 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
8027
8028 hlua_sendlog(htxn->s->be, level, msg);
8029 return 0;
8030}
8031
8032__LJMP static int hlua_txn_log_debug(lua_State *L)
8033{
8034 const char *msg;
8035 struct hlua_txn *htxn;
8036
8037 MAY_LJMP(check_args(L, 2, "Debug"));
8038 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8039 msg = MAY_LJMP(luaL_checkstring(L, 2));
8040 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
8041 return 0;
8042}
8043
8044__LJMP static int hlua_txn_log_info(lua_State *L)
8045{
8046 const char *msg;
8047 struct hlua_txn *htxn;
8048
8049 MAY_LJMP(check_args(L, 2, "Info"));
8050 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8051 msg = MAY_LJMP(luaL_checkstring(L, 2));
8052 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
8053 return 0;
8054}
8055
8056__LJMP static int hlua_txn_log_warning(lua_State *L)
8057{
8058 const char *msg;
8059 struct hlua_txn *htxn;
8060
8061 MAY_LJMP(check_args(L, 2, "Warning"));
8062 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8063 msg = MAY_LJMP(luaL_checkstring(L, 2));
8064 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
8065 return 0;
8066}
8067
8068__LJMP static int hlua_txn_log_alert(lua_State *L)
8069{
8070 const char *msg;
8071 struct hlua_txn *htxn;
8072
8073 MAY_LJMP(check_args(L, 2, "Alert"));
8074 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8075 msg = MAY_LJMP(luaL_checkstring(L, 2));
8076 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
8077 return 0;
8078}
8079
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01008080__LJMP static int hlua_txn_set_loglevel(lua_State *L)
8081{
8082 struct hlua_txn *htxn;
8083 int ll;
8084
8085 MAY_LJMP(check_args(L, 2, "set_loglevel"));
8086 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8087 ll = MAY_LJMP(luaL_checkinteger(L, 2));
8088
8089 if (ll < 0 || ll > 7)
8090 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
8091
8092 htxn->s->logs.level = ll;
8093 return 0;
8094}
8095
8096__LJMP static int hlua_txn_set_tos(lua_State *L)
8097{
8098 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01008099 int tos;
8100
8101 MAY_LJMP(check_args(L, 2, "set_tos"));
8102 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8103 tos = MAY_LJMP(luaL_checkinteger(L, 2));
8104
Willy Tarreau1a18b542018-12-11 16:37:42 +01008105 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01008106 return 0;
8107}
8108
8109__LJMP static int hlua_txn_set_mark(lua_State *L)
8110{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01008111 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01008112 int mark;
8113
8114 MAY_LJMP(check_args(L, 2, "set_mark"));
8115 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8116 mark = MAY_LJMP(luaL_checkinteger(L, 2));
8117
Lukas Tribus579e3e32019-08-11 18:03:45 +02008118 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01008119 return 0;
8120}
8121
Patrick Hemmer268a7072018-05-11 12:52:31 -04008122__LJMP static int hlua_txn_set_priority_class(lua_State *L)
8123{
8124 struct hlua_txn *htxn;
8125
8126 MAY_LJMP(check_args(L, 2, "set_priority_class"));
8127 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8128 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
8129 return 0;
8130}
8131
8132__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
8133{
8134 struct hlua_txn *htxn;
8135
8136 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
8137 htxn = MAY_LJMP(hlua_checktxn(L, 1));
8138 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
8139 return 0;
8140}
8141
Christopher Faulet700d9e82020-01-31 12:21:52 +01008142/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05008143 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01008144 * message and terminate the transaction. It returns 1 on success and 0 on
8145 * error. The Reply must be on top of the stack.
8146 */
8147__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
8148{
8149 struct htx *htx;
8150 struct htx_sl *sl;
8151 struct h1m h1m;
8152 const char *status, *reason, *body;
8153 size_t status_len, reason_len, body_len;
8154 int ret, code, flags;
8155
8156 code = 200;
8157 status = "200";
8158 status_len = 3;
8159 ret = lua_getfield(L, -1, "status");
8160 if (ret == LUA_TNUMBER) {
8161 code = lua_tointeger(L, -1);
8162 status = lua_tolstring(L, -1, &status_len);
8163 }
8164 lua_pop(L, 1);
8165
8166 reason = http_get_reason(code);
8167 reason_len = strlen(reason);
8168 ret = lua_getfield(L, -1, "reason");
8169 if (ret == LUA_TSTRING)
8170 reason = lua_tolstring(L, -1, &reason_len);
8171 lua_pop(L, 1);
8172
8173 body = NULL;
8174 body_len = 0;
8175 ret = lua_getfield(L, -1, "body");
8176 if (ret == LUA_TSTRING)
8177 body = lua_tolstring(L, -1, &body_len);
8178 lua_pop(L, 1);
8179
8180 /* Prepare the response before inserting the headers */
8181 h1m_init_res(&h1m);
8182 htx = htx_from_buf(&s->res.buf);
8183 channel_htx_truncate(&s->res, htx);
8184 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
8185 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
8186 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
8187 ist2(status, status_len), ist2(reason, reason_len));
8188 }
8189 else {
8190 flags = HTX_SL_F_IS_RESP;
8191 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
8192 ist2(status, status_len), ist2(reason, reason_len));
8193 }
8194 if (!sl)
8195 goto fail;
8196 sl->info.res.status = code;
8197
8198 /* Push in the stack the "headers" entry. */
8199 ret = lua_getfield(L, -1, "headers");
8200 if (ret != LUA_TTABLE)
8201 goto skip_headers;
8202
8203 lua_pushnil(L);
8204 while (lua_next(L, -2) != 0) {
8205 struct ist name, value;
8206 const char *n, *v;
8207 size_t nlen, vlen;
8208
8209 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
8210 /* Skip element if the key is not a string or if the value is not a table */
8211 goto next_hdr;
8212 }
8213
8214 n = lua_tolstring(L, -2, &nlen);
8215 name = ist2(n, nlen);
8216 if (isteqi(name, ist("content-length"))) {
8217 /* Always skip content-length header. It will be added
8218 * later with the correct len
8219 */
8220 goto next_hdr;
8221 }
8222
8223 /* Loop on header's values */
8224 lua_pushnil(L);
8225 while (lua_next(L, -2)) {
8226 if (!lua_isstring(L, -1)) {
8227 /* Skip the value if it is not a string */
8228 goto next_value;
8229 }
8230
8231 v = lua_tolstring(L, -1, &vlen);
8232 value = ist2(v, vlen);
8233
8234 if (isteqi(name, ist("transfer-encoding")))
8235 h1_parse_xfer_enc_header(&h1m, value);
8236 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
8237 goto fail;
8238
8239 next_value:
8240 lua_pop(L, 1);
8241 }
8242
8243 next_hdr:
8244 lua_pop(L, 1);
8245 }
8246 skip_headers:
8247 lua_pop(L, 1);
8248
8249 /* Update h1m flags: CLEN is set if CHNK is not present */
8250 if (!(h1m.flags & H1_MF_CHNK)) {
8251 const char *clen = ultoa(body_len);
8252
8253 h1m.flags |= H1_MF_CLEN;
8254 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
8255 goto fail;
8256 }
8257 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
8258 h1m.flags |= H1_MF_XFER_LEN;
8259
8260 /* Update HTX start-line flags */
8261 if (h1m.flags & H1_MF_XFER_ENC)
8262 flags |= HTX_SL_F_XFER_ENC;
8263 if (h1m.flags & H1_MF_XFER_LEN) {
8264 flags |= HTX_SL_F_XFER_LEN;
8265 if (h1m.flags & H1_MF_CHNK)
8266 flags |= HTX_SL_F_CHNK;
8267 else if (h1m.flags & H1_MF_CLEN)
8268 flags |= HTX_SL_F_CLEN;
8269 if (h1m.body_len == 0)
8270 flags |= HTX_SL_F_BODYLESS;
8271 }
8272 sl->flags |= flags;
8273
8274
8275 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008276 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01008277 goto fail;
8278
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008279 htx->flags |= HTX_FL_EOM;
8280
Christopher Faulet700d9e82020-01-31 12:21:52 +01008281 /* Now, forward the response and terminate the transaction */
8282 s->txn->status = code;
8283 htx_to_buf(htx, &s->res.buf);
8284 if (!http_forward_proxy_resp(s, 1))
8285 goto fail;
8286
8287 return 1;
8288
8289 fail:
8290 channel_htx_truncate(&s->res, htx);
8291 return 0;
8292}
8293
8294/* Terminate a transaction if called from a lua action. For TCP streams,
8295 * processing is just aborted. Nothing is returned to the client and all
8296 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
8297 * is forwarded to the client before terminating the transaction. On success,
8298 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
8299 * with ACT_RET_ERR code. If this function is not called from a lua action, it
8300 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008301 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008302__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008303{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008304 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01008305 struct stream *s;
8306 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008307
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008308 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008309
Christopher Faulet700d9e82020-01-31 12:21:52 +01008310 /* If the flags NOTERM is set, we cannot terminate the session, so we
8311 * just end the execution of the current lua code. */
8312 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008313 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008314
Christopher Faulet700d9e82020-01-31 12:21:52 +01008315 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008316 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008317 struct channel *req = &s->req;
8318 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01008319
Christopher Faulet700d9e82020-01-31 12:21:52 +01008320 channel_auto_read(req);
8321 channel_abort(req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008322 channel_erase(req);
8323
Christopher Faulet700d9e82020-01-31 12:21:52 +01008324 channel_auto_read(res);
8325 channel_auto_close(res);
Christopher Faulet12762f02023-04-13 15:40:10 +02008326 sc_schedule_abort(s->scb);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008327
8328 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
8329 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008330 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02008331
Christopher Faulet700d9e82020-01-31 12:21:52 +01008332 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
8333 /* No reply or invalid reply */
8334 s->txn->status = 0;
8335 http_reply_and_close(s, 0, NULL);
8336 }
8337 else {
8338 /* Remove extra args to have the reply on top of the stack */
8339 if (lua_gettop(L) > 2)
8340 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008341
Christopher Faulet700d9e82020-01-31 12:21:52 +01008342 if (!hlua_txn_forward_reply(L, s)) {
8343 if (!(s->flags & SF_ERR_MASK))
8344 s->flags |= SF_ERR_PRXCOND;
8345 lua_pushinteger(L, ACT_RET_ERR);
8346 WILL_LJMP(hlua_done(L));
8347 return 0; /* Never reached */
8348 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02008349 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008350
Christopher Faulet700d9e82020-01-31 12:21:52 +01008351 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
8352 if (htxn->dir == SMP_OPT_DIR_REQ) {
8353 /* let's log the request time */
Willy Tarreau69530f52023-04-28 09:16:15 +02008354 s->logs.request_ts = now_ns;
Christopher Faulet700d9e82020-01-31 12:21:52 +01008355 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02008356 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008357 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008358
Christopher Faulet700d9e82020-01-31 12:21:52 +01008359 done:
8360 if (!(s->flags & SF_ERR_MASK))
8361 s->flags |= SF_ERR_LOCAL;
8362 if (!(s->flags & SF_FINST_MASK))
8363 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008364
Christopher Faulete48d1dc2021-08-13 14:11:17 +02008365 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX)
8366 lua_pushinteger(L, -1);
8367 else
8368 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008369 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008370 return 0;
8371}
8372
Christopher Faulet700d9e82020-01-31 12:21:52 +01008373/*
8374 *
8375 *
8376 * Class REPLY
8377 *
8378 *
8379 */
8380
8381/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
8382 * free slots, the function fails and returns 0;
8383 */
8384static int hlua_txn_reply_new(lua_State *L)
8385{
8386 struct hlua_txn *htxn;
8387 const char *reason, *body = NULL;
8388 int ret, status;
8389
8390 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008391 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008392 hlua_pusherror(L, "txn object is not an HTTP transaction.");
8393 WILL_LJMP(lua_error(L));
8394 }
8395
8396 /* Default value */
8397 status = 200;
8398 reason = http_get_reason(status);
8399
8400 if (lua_istable(L, 2)) {
8401 /* load status and reason from the table argument at index 2 */
8402 ret = lua_getfield(L, 2, "status");
8403 if (ret == LUA_TNIL)
8404 goto reason;
8405 else if (ret != LUA_TNUMBER) {
8406 /* invalid status: ignore the reason */
8407 goto body;
8408 }
8409 status = lua_tointeger(L, -1);
8410
8411 reason:
8412 lua_pop(L, 1); /* restore the stack: remove status */
8413 ret = lua_getfield(L, 2, "reason");
8414 if (ret == LUA_TSTRING)
8415 reason = lua_tostring(L, -1);
8416
8417 body:
8418 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
8419 ret = lua_getfield(L, 2, "body");
8420 if (ret == LUA_TSTRING)
8421 body = lua_tostring(L, -1);
8422 lua_pop(L, 1); /* restore the stack: remove body */
8423 }
8424
8425 /* Create the Reply table */
8426 lua_newtable(L);
8427
8428 /* Add status element */
8429 lua_pushstring(L, "status");
8430 lua_pushinteger(L, status);
8431 lua_settable(L, -3);
8432
8433 /* Add reason element */
8434 reason = http_get_reason(status);
8435 lua_pushstring(L, "reason");
8436 lua_pushstring(L, reason);
8437 lua_settable(L, -3);
8438
8439 /* Add body element, nil if undefined */
8440 lua_pushstring(L, "body");
8441 if (body)
8442 lua_pushstring(L, body);
8443 else
8444 lua_pushnil(L);
8445 lua_settable(L, -3);
8446
8447 /* Add headers element */
8448 lua_pushstring(L, "headers");
8449 lua_newtable(L);
8450
8451 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8452 if (lua_istable(L, 2)) {
8453 /* load headers from the table argument at index 2. If it is a table, copy it. */
8454 ret = lua_getfield(L, 2, "headers");
8455 if (ret == LUA_TTABLE) {
8456 /* stack: [ ... <headers:table>, <table> ] */
8457 lua_pushnil(L);
8458 while (lua_next(L, -2) != 0) {
8459 /* stack: [ ... <headers:table>, <table>, k, v] */
8460 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
8461 /* invalid value type, skip it */
8462 lua_pop(L, 1);
8463 continue;
8464 }
8465
8466
8467 /* Duplicate the key and swap it with the value. */
8468 lua_pushvalue(L, -2);
8469 lua_insert(L, -2);
8470 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
8471
8472 lua_newtable(L);
8473 lua_insert(L, -2);
8474 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
8475
8476 if (lua_isstring(L, -1)) {
8477 /* push the value in the inner table */
8478 lua_rawseti(L, -2, 1);
8479 }
8480 else { /* table */
8481 lua_pushnil(L);
8482 while (lua_next(L, -2) != 0) {
8483 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
8484 if (!lua_isstring(L, -1)) {
8485 /* invalid value type, skip it*/
8486 lua_pop(L, 1);
8487 continue;
8488 }
8489 /* push the value in the inner table */
8490 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
8491 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
8492 }
8493 lua_pop(L, 1);
8494 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
8495 }
8496
8497 /* push (k,v) on the stack in the headers table:
8498 * stack: [ ... <headers:table>, <table>, k, k, v ]
8499 */
8500 lua_settable(L, -5);
8501 /* stack: [ ... <headers:table>, <table>, k ] */
8502 }
8503 }
8504 lua_pop(L, 1);
8505 }
8506 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8507 lua_settable(L, -3);
8508 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
8509
8510 /* Pop a class sesison metatable and affect it to the userdata. */
8511 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
8512 lua_setmetatable(L, -2);
8513 return 1;
8514}
8515
8516/* Set the reply status code, and optionally the reason. If no reason is
8517 * provided, the default one corresponding to the status code is used.
8518 */
8519__LJMP static int hlua_txn_reply_set_status(lua_State *L)
8520{
8521 int status = MAY_LJMP(luaL_checkinteger(L, 2));
8522 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
8523
8524 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008525 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008526
8527 if (status < 100 || status > 599) {
8528 lua_pushboolean(L, 0);
8529 return 1;
8530 }
8531 if (!reason)
8532 reason = http_get_reason(status);
8533
8534 lua_pushinteger(L, status);
8535 lua_setfield(L, 1, "status");
8536
8537 lua_pushstring(L, reason);
8538 lua_setfield(L, 1, "reason");
8539
8540 lua_pushboolean(L, 1);
8541 return 1;
8542}
8543
8544/* Add a header into the reply object. Each header name is associated to an
8545 * array of values in the "headers" table. If the header name is not found, a
8546 * new entry is created.
8547 */
8548__LJMP static int hlua_txn_reply_add_header(lua_State *L)
8549{
8550 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8551 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
8552 int ret;
8553
8554 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008555 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008556
8557 /* Push in the stack the "headers" entry. */
8558 ret = lua_getfield(L, 1, "headers");
8559 if (ret != LUA_TTABLE) {
8560 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
8561 WILL_LJMP(lua_error(L));
8562 }
8563
8564 /* check if the header is already registered. If not, register it. */
8565 ret = lua_getfield(L, -1, name);
8566 if (ret == LUA_TNIL) {
8567 /* Entry not found. */
8568 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
8569
8570 /* Insert the new header name in the array in the top of the stack.
8571 * It left the new array in the top of the stack.
8572 */
8573 lua_newtable(L);
8574 lua_pushstring(L, name);
8575 lua_pushvalue(L, -2);
8576 lua_settable(L, -4);
8577 }
8578 else if (ret != LUA_TTABLE) {
8579 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
8580 WILL_LJMP(lua_error(L));
8581 }
8582
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008583 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01008584 * the header value as new entry.
8585 */
8586 lua_pushstring(L, value);
8587 ret = lua_rawlen(L, -2);
8588 lua_rawseti(L, -2, ret + 1);
8589
8590 lua_pushboolean(L, 1);
8591 return 1;
8592}
8593
8594/* Remove all occurrences of a given header name. */
8595__LJMP static int hlua_txn_reply_del_header(lua_State *L)
8596{
8597 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8598 int ret;
8599
8600 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008601 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008602
8603 /* Push in the stack the "headers" entry. */
8604 ret = lua_getfield(L, 1, "headers");
8605 if (ret != LUA_TTABLE) {
8606 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
8607 WILL_LJMP(lua_error(L));
8608 }
8609
8610 lua_pushstring(L, name);
8611 lua_pushnil(L);
8612 lua_settable(L, -3);
8613
8614 lua_pushboolean(L, 1);
8615 return 1;
8616}
8617
8618/* Set the reply's body. Overwrite any existing entry. */
8619__LJMP static int hlua_txn_reply_set_body(lua_State *L)
8620{
8621 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
8622
8623 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008624 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008625
8626 lua_pushstring(L, payload);
8627 lua_setfield(L, 1, "body");
8628
8629 lua_pushboolean(L, 1);
8630 return 1;
8631}
8632
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008633__LJMP static int hlua_log(lua_State *L)
8634{
8635 int level;
8636 const char *msg;
8637
8638 MAY_LJMP(check_args(L, 2, "log"));
8639 level = MAY_LJMP(luaL_checkinteger(L, 1));
8640 msg = MAY_LJMP(luaL_checkstring(L, 2));
8641
8642 if (level < 0 || level >= NB_LOG_LEVELS)
8643 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
8644
8645 hlua_sendlog(NULL, level, msg);
8646 return 0;
8647}
8648
8649__LJMP static int hlua_log_debug(lua_State *L)
8650{
8651 const char *msg;
8652
8653 MAY_LJMP(check_args(L, 1, "debug"));
8654 msg = MAY_LJMP(luaL_checkstring(L, 1));
8655 hlua_sendlog(NULL, LOG_DEBUG, msg);
8656 return 0;
8657}
8658
8659__LJMP static int hlua_log_info(lua_State *L)
8660{
8661 const char *msg;
8662
8663 MAY_LJMP(check_args(L, 1, "info"));
8664 msg = MAY_LJMP(luaL_checkstring(L, 1));
8665 hlua_sendlog(NULL, LOG_INFO, msg);
8666 return 0;
8667}
8668
8669__LJMP static int hlua_log_warning(lua_State *L)
8670{
8671 const char *msg;
8672
8673 MAY_LJMP(check_args(L, 1, "warning"));
8674 msg = MAY_LJMP(luaL_checkstring(L, 1));
8675 hlua_sendlog(NULL, LOG_WARNING, msg);
8676 return 0;
8677}
8678
8679__LJMP static int hlua_log_alert(lua_State *L)
8680{
8681 const char *msg;
8682
8683 MAY_LJMP(check_args(L, 1, "alert"));
8684 msg = MAY_LJMP(luaL_checkstring(L, 1));
8685 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008686 return 0;
8687}
8688
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008689__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008690{
8691 int wakeup_ms = lua_tointeger(L, -1);
Willy Tarreau12c02702021-09-30 16:12:31 +02008692 if (!tick_is_expired(wakeup_ms, now_ms))
Willy Tarreau9635e032018-10-16 17:52:55 +02008693 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008694 return 0;
8695}
8696
8697__LJMP static int hlua_sleep(lua_State *L)
8698{
8699 unsigned int delay;
Aurelien DARRAGON2a9764b2023-04-04 18:41:04 +02008700 int wakeup_ms; // tick value
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008701
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008702 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008703
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008704 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008705 wakeup_ms = tick_add(now_ms, delay);
8706 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008707
Willy Tarreau9635e032018-10-16 17:52:55 +02008708 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008709 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008710}
8711
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008712__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008713{
8714 unsigned int delay;
Aurelien DARRAGON2a9764b2023-04-04 18:41:04 +02008715 int wakeup_ms; // tick value
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008716
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008717 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008718
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008719 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008720 wakeup_ms = tick_add(now_ms, delay);
8721 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008722
Willy Tarreau9635e032018-10-16 17:52:55 +02008723 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008724 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008725}
8726
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008727/* This functionis an LUA binding. it permits to give back
8728 * the hand at the HAProxy scheduler. It is used when the
8729 * LUA processing consumes a lot of time.
8730 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008731__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008732{
8733 return 0;
8734}
8735
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008736__LJMP static int hlua_yield(lua_State *L)
8737{
Willy Tarreau9635e032018-10-16 17:52:55 +02008738 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008739 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008740}
8741
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008742/* This function change the nice of the currently executed
8743 * task. It is used set low or high priority at the current
8744 * task.
8745 */
Willy Tarreau59551662015-03-10 14:23:13 +01008746__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008747{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008748 struct hlua *hlua;
8749 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008750
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008751 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008752 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008753
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008754 /* Get hlua struct, or NULL if we execute from main lua state */
8755 hlua = hlua_gethlua(L);
8756
8757 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008758 if (!hlua || !hlua->task)
8759 return 0;
8760
8761 if (nice < -1024)
8762 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008763 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008764 nice = 1024;
8765
8766 hlua->task->nice = nice;
8767 return 0;
8768}
8769
Aurelien DARRAGON8cd620b2023-04-07 17:37:46 +02008770/* safe lua coroutine.create() function:
8771 *
8772 * This is a simple wrapper for coroutine.create() that
8773 * ensures the current hlua state ctx is available from
8774 * the new subroutine state
8775 */
8776__LJMP static int hlua_coroutine_create(lua_State *L)
8777{
8778 lua_State *new; /* new coroutine state */
8779 struct hlua **hlua_store;
8780 struct hlua *hlua = hlua_gethlua(L);
8781
8782 new = lua_newthread(L);
8783 if (!new)
8784 return 0;
8785
8786 hlua_store = lua_getextraspace(new);
8787 /* Expose current hlua ctx on new lua thread
8788 * (hlua_gethlua() will properly return the last "known"
8789 * hlua ctx instead of NULL when it is called from such coroutines)
8790 */
8791 *hlua_store = hlua;
8792
8793 /* new lua thread is on the top of the stack, we
8794 * need to duplicate first stack argument (<f> from coroutine.create(<f>))
8795 * on the top of the stack to be able to use xmove() to move it on the new
8796 * stack
8797 */
8798 lua_pushvalue(L, 1);
8799 /* move <f> function to the new stack */
8800 lua_xmove(L, new, 1);
8801 /* new lua thread is back at the top of the stack */
8802 return 1;
8803}
8804
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008805/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008806 * HAProxy task subsystem when the task is awaked. The LUA runtime can
8807 * return an E_AGAIN signal, the emmiter of this signal must set a
8808 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008809 *
8810 * Task wrapper are longjmp safe because the only one Lua code
8811 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008812 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01008813struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008814{
Olivier Houchard9f6af332018-05-25 14:04:04 +02008815 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008816 enum hlua_exec status;
8817
Willy Tarreau6ef52f42022-06-15 14:19:48 +02008818 if (task->tid < 0)
8819 task->tid = tid;
8820
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008821 /* If it is the first call to the task, we must initialize the
8822 * execution timeouts.
8823 */
8824 if (!HLUA_IS_RUNNING(hlua))
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01008825 hlua_timer_init(&hlua->timer, hlua_timeout_task);
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008826
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008827 /* Execute the Lua code. */
8828 status = hlua_ctx_resume(hlua, 1);
8829
8830 switch (status) {
8831 /* finished or yield */
8832 case HLUA_E_OK:
8833 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008834 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02008835 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008836 break;
8837
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01008838 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01008839 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02008840 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008841 break;
8842
8843 /* finished with error. */
Aurelien DARRAGON79544102022-11-24 14:27:15 +01008844 case HLUA_E_ETMOUT:
8845 SEND_ERR(NULL, "Lua task: execution timeout.\n");
8846 goto err_task_abort;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008847 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008848 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Aurelien DARRAGON79544102022-11-24 14:27:15 +01008849 goto err_task_abort;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008850 case HLUA_E_ERR:
8851 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008852 SEND_ERR(NULL, "Lua task: unknown error.\n");
Aurelien DARRAGON79544102022-11-24 14:27:15 +01008853 err_task_abort:
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008854 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008855 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02008856 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008857 break;
8858 }
Emeric Brun253e53e2017-10-17 18:58:40 +02008859 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008860}
8861
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +02008862/* Helper function to prepare the lua ctx for a given stream
8863 *
Aurelien DARRAGON02493662023-08-09 15:19:56 +02008864 * ctx will be enforced in <state_id> parent stack on initial creation.
8865 * If s->hlua->state_id differs from <state_id>, which may happen at
8866 * runtime since existing stream hlua ctx will be reused for other
8867 * "independent" (but stream-related) lua executions, hlua will be
8868 * recreated with the expected state id.
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +02008869 *
8870 * Returns 1 for success and 0 for failure
8871 */
8872static int hlua_stream_ctx_prepare(struct stream *s, int state_id)
8873{
8874 /* In the execution wrappers linked with a stream, the
8875 * Lua context can be not initialized. This behavior
8876 * permits to save performances because a systematic
8877 * Lua initialization cause 5% performances loss.
8878 */
Aurelien DARRAGON02493662023-08-09 15:19:56 +02008879 ctx_renew:
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +02008880 if (!s->hlua) {
8881 struct hlua *hlua;
8882
8883 hlua = pool_alloc(pool_head_hlua);
8884 if (!hlua)
8885 return 0;
8886 HLUA_INIT(hlua);
8887 if (!hlua_ctx_init(hlua, state_id, s->task)) {
8888 pool_free(pool_head_hlua, hlua);
8889 return 0;
8890 }
8891 s->hlua = hlua;
8892 }
Aurelien DARRAGON02493662023-08-09 15:19:56 +02008893 else if (s->hlua->state_id != state_id) {
8894 /* ctx already created, but not in proper state.
8895 * It should only happen after the previous execution is
8896 * finished, otherwise it's probably a bug since we don't
8897 * want to abort unfinished job..
8898 */
8899 BUG_ON(HLUA_IS_RUNNING(s->hlua));
8900 hlua_ctx_destroy(s->hlua);
8901 s->hlua = NULL;
8902 goto ctx_renew;
8903 }
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +02008904 return 1;
8905}
8906
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008907/* This function is an LUA binding that register LUA function to be
8908 * executed after the HAProxy configuration parsing and before the
8909 * HAProxy scheduler starts. This function expect only one LUA
8910 * argument that is a function. This function returns nothing, but
8911 * throws if an error is encountered.
8912 */
8913__LJMP static int hlua_register_init(lua_State *L)
8914{
8915 struct hlua_init_function *init;
8916 int ref;
8917
8918 MAY_LJMP(check_args(L, 1, "register_init"));
8919
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01008920 if (hlua_gethlua(L)) {
8921 /* runtime processing */
8922 WILL_LJMP(luaL_error(L, "register_init: not available outside of body context"));
8923 }
8924
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008925 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8926
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008927 init = calloc(1, sizeof(*init));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008928 if (!init) {
8929 hlua_unref(L, ref);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008930 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008931 }
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008932
8933 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02008934 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008935 return 0;
8936}
8937
Ilya Shipitsin6f86eaa2022-11-30 16:22:42 +05008938/* This function is an LUA binding. It permits to register a task
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008939 * executed in parallel of the main HAroxy activity. The task is
8940 * created and it is set in the HAProxy scheduler. It can be called
8941 * from the "init" section, "post init" or during the runtime.
8942 *
8943 * Lua prototype:
8944 *
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008945 * <none> core.register_task(<function>[, <arg1>[, <arg2>[, ...[, <arg4>]]]])
8946 *
8947 * <arg1..4> are optional arguments that will be provided to <function>
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008948 */
Aurelien DARRAGONe0b16352023-04-21 17:38:37 +02008949__LJMP static int hlua_register_task(lua_State *L)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008950{
Christopher Faulet5294ec02021-04-12 12:24:47 +02008951 struct hlua *hlua = NULL;
8952 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008953 int ref;
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008954 int nb_arg;
8955 int it;
8956 int arg_ref[4]; /* optional arguments */
Thierry Fournier021d9862020-11-28 23:42:03 +01008957 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008958
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008959 nb_arg = lua_gettop(L);
8960 if (nb_arg < 1)
8961 WILL_LJMP(luaL_error(L, "register_task: <func> argument is required"));
8962 else if (nb_arg > 5)
8963 WILL_LJMP(luaL_error(L, "register_task: no more that 4 optional arguments may be provided"));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008964
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008965 /* first arg: function ref */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008966 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8967
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008968 /* extract optional args (if any) */
8969 it = 0;
8970 while (--nb_arg) {
8971 lua_pushvalue(L, 2 + it);
8972 arg_ref[it] = hlua_ref(L); /* get arg reference */
8973 it += 1;
8974 }
8975 nb_arg = it;
8976
Thierry Fournier75fc0292020-11-28 13:18:56 +01008977 /* Get the reference state. If the reference is NULL, L is the master
8978 * state, otherwise hlua->T is.
8979 */
8980 hlua = hlua_gethlua(L);
8981 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01008982 /* we are in runtime processing */
8983 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008984 else
Thierry Fournier021d9862020-11-28 23:42:03 +01008985 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01008986 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008987
Willy Tarreaubafbe012017-11-24 17:34:44 +01008988 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008989 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008990 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008991 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008992
Thierry Fournier59f11be2020-11-29 00:37:41 +01008993 /* We are in the common lua state, execute the task anywhere,
8994 * otherwise, inherit the current thread identifier
8995 */
8996 if (state_id == 0)
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008997 task = task_new_anywhere();
Thierry Fournier59f11be2020-11-29 00:37:41 +01008998 else
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008999 task = task_new_here();
Willy Tarreaue09101e2018-10-16 17:37:12 +02009000 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02009001 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02009002
Thierry FOURNIER24f33532015-01-23 12:13:00 +01009003 task->context = hlua;
9004 task->process = hlua_process_task;
9005
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01009006 if (!hlua_ctx_init(hlua, state_id, task))
Christopher Faulet5294ec02021-04-12 12:24:47 +02009007 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01009008
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01009009 /* Ensure there is enough space on the stack for the function
9010 * plus optional arguments
9011 */
9012 if (!lua_checkstack(hlua->T, (1 + nb_arg)))
9013 goto alloc_error;
9014
Thierry FOURNIER24f33532015-01-23 12:13:00 +01009015 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009016 hlua_pushref(hlua->T, ref);
Aurelien DARRAGONbe58d662023-03-13 14:09:21 +01009017 /* function ref not needed anymore since it was pushed to the substack */
9018 hlua_unref(L, ref);
9019
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01009020 hlua->nargs = nb_arg;
9021
9022 /* push optional arguments to the function */
9023 for (it = 0; it < nb_arg; it++) {
9024 /* push arg to the stack */
9025 hlua_pushref(hlua->T, arg_ref[it]);
9026 /* arg ref not needed anymore since it was pushed to the substack */
9027 hlua_unref(L, arg_ref[it]);
9028 }
Thierry FOURNIER24f33532015-01-23 12:13:00 +01009029
9030 /* Schedule task. */
Willy Tarreaue3957f82021-09-30 16:17:37 +02009031 task_wakeup(task, TASK_WOKEN_INIT);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01009032
9033 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02009034
9035 alloc_error:
9036 task_destroy(task);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009037 hlua_unref(L, ref);
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01009038 for (it = 0; it < nb_arg; it++) {
9039 hlua_unref(L, arg_ref[it]);
9040 }
Christopher Faulet5294ec02021-04-12 12:24:47 +02009041 hlua_ctx_destroy(hlua);
9042 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9043 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01009044}
9045
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009046/* called from unsafe location */
9047static void hlua_event_subscription_destroy(struct hlua_event_sub *hlua_sub)
9048{
9049 /* hlua cleanup */
9050
9051 hlua_lock(hlua_sub->hlua);
9052 /* registry is shared between coroutines */
9053 hlua_unref(hlua_sub->hlua->T, hlua_sub->fcn_ref);
9054 hlua_unlock(hlua_sub->hlua);
9055
9056 hlua_ctx_destroy(hlua_sub->hlua);
9057
9058 /* free */
9059 pool_free(pool_head_hlua_event_sub, hlua_sub);
9060}
9061
9062/* single event handler: hlua ctx is shared between multiple events handlers
9063 * issued from the same subscription. Thus, it is not destroyed when the event
9064 * is processed: it is destroyed when no more events are expected for the
9065 * subscription (ie: when the subscription ends).
9066 *
9067 * Moreover, events are processed sequentially within the subscription:
9068 * one event must be fully processed before another one may be processed.
9069 * This ensures proper consistency for lua event handling from an ordering
9070 * point of view. This is especially useful with server events for example
9071 * where ADD/DEL/UP/DOWN events ordering really matters to trigger specific
9072 * actions from lua (e.g.: sending emails or making API calls).
9073 *
9074 * Due to this design, each lua event handler is pleased to process the event
9075 * as fast as possible to prevent the event queue from growing up.
9076 * Strictly speaking, there is no runtime limit for the callback function
9077 * (timeout set to default task timeout), but if the event queue goes past
9078 * the limit of unconsumed events an error will be reported and the
9079 * susbscription will pause itself for as long as it takes for the handler to
9080 * catch up (events will be lost as a result).
9081 * If the event handler does not need the sequential ordering and wants to
9082 * process multiple events at a time, it may spawn a new side-task using
9083 * 'core.register_task' to delegate the event handling and make parallel event
9084 * processing within the same subscription set.
9085 */
9086static void hlua_event_handler(struct hlua *hlua)
9087{
9088 enum hlua_exec status;
9089
9090 /* If it is the first call to the task, we must initialize the
9091 * execution timeouts.
9092 */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01009093 if (!HLUA_IS_RUNNING(hlua))
9094 hlua_timer_init(&hlua->timer, hlua_timeout_task);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009095
9096 /* make sure to reset the task expiry before each hlua_ctx_resume()
9097 * since the task is re-used for multiple cb function calls
9098 * We couldn't risk to have t->expire pointing to a past date because
9099 * it was set during last function invocation but was never reset since
9100 * (ie: E_AGAIN)
9101 */
9102 hlua->task->expire = TICK_ETERNITY;
9103
9104 /* Execute the Lua code. */
9105 status = hlua_ctx_resume(hlua, 1);
9106
9107 switch (status) {
9108 /* finished or yield */
9109 case HLUA_E_OK:
9110 break;
9111
9112 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
9113 notification_gc(&hlua->com);
9114 hlua->task->expire = hlua->wake_time;
9115 break;
9116
9117 /* finished with error. */
9118 case HLUA_E_ETMOUT:
9119 SEND_ERR(NULL, "Lua event_hdl: execution timeout.\n");
9120 break;
9121
9122 case HLUA_E_ERRMSG:
9123 SEND_ERR(NULL, "Lua event_hdl: %s.\n", lua_tostring(hlua->T, -1));
9124 break;
9125
9126 case HLUA_E_ERR:
9127 default:
9128 SEND_ERR(NULL, "Lua event_hdl: unknown error.\n");
9129 break;
9130 }
9131}
9132
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +02009133__LJMP static void hlua_event_hdl_cb_push_event_checkres(lua_State *L,
9134 struct event_hdl_cb_data_server_checkres *check)
9135{
9136 lua_pushstring(L, "agent");
9137 lua_pushboolean(L, check->agent);
9138 lua_settable(L, -3);
9139 lua_pushstring(L, "result");
9140 switch (check->result) {
9141 case CHK_RES_FAILED:
9142 lua_pushstring(L, "FAILED");
9143 break;
9144 case CHK_RES_PASSED:
9145 lua_pushstring(L, "PASSED");
9146 break;
9147 case CHK_RES_CONDPASS:
9148 lua_pushstring(L, "CONDPASS");
9149 break;
9150 default:
9151 lua_pushnil(L);
9152 break;
9153 }
9154 lua_settable(L, -3);
9155
9156 lua_pushstring(L, "duration");
9157 lua_pushinteger(L, check->duration);
9158 lua_settable(L, -3);
9159
9160 lua_pushstring(L, "reason");
9161 lua_newtable(L);
9162
9163 lua_pushstring(L, "short");
9164 lua_pushstring(L, get_check_status_info(check->reason.status));
9165 lua_settable(L, -3);
9166 lua_pushstring(L, "desc");
9167 lua_pushstring(L, get_check_status_description(check->reason.status));
9168 lua_settable(L, -3);
9169 if (check->reason.status >= HCHK_STATUS_L57DATA) {
9170 /* code only available when the check reached data analysis stage */
9171 lua_pushstring(L, "code");
9172 lua_pushinteger(L, check->reason.code);
9173 lua_settable(L, -3);
9174 }
9175
9176 lua_settable(L, -3); /* reason table */
9177
9178 lua_pushstring(L, "health");
9179 lua_newtable(L);
9180
9181 lua_pushstring(L, "cur");
9182 lua_pushinteger(L, check->health.cur);
9183 lua_settable(L, -3);
9184 lua_pushstring(L, "rise");
9185 lua_pushinteger(L, check->health.rise);
9186 lua_settable(L, -3);
9187 lua_pushstring(L, "fall");
9188 lua_pushinteger(L, check->health.fall);
9189 lua_settable(L, -3);
9190
9191 lua_settable(L, -3); /* health table */
9192}
9193
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009194/* This function pushes various arguments such as event type and event data to
9195 * the lua function that will be called to consume the event.
9196 */
9197__LJMP static void hlua_event_hdl_cb_push_args(struct hlua_event_sub *hlua_sub,
9198 struct event_hdl_async_event *e)
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009199{
9200 struct hlua *hlua = hlua_sub->hlua;
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009201 struct event_hdl_sub_type event = e->type;
9202 void *data = e->data;
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009203
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009204 /* push event type */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009205 hlua->nargs = 1;
9206 lua_pushstring(hlua->T, event_hdl_sub_type_to_string(event));
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009207
9208 /* push event data (according to event type) */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009209 if (event_hdl_sub_family_equal(EVENT_HDL_SUB_SERVER, event)) {
9210 struct event_hdl_cb_data_server *e_server = data;
9211 struct proxy *px;
9212 struct server *server;
9213
9214 hlua->nargs += 1;
9215 lua_newtable(hlua->T);
9216 /* Add server name */
9217 lua_pushstring(hlua->T, "name");
9218 lua_pushstring(hlua->T, e_server->safe.name);
9219 lua_settable(hlua->T, -3);
9220 /* Add server puid */
9221 lua_pushstring(hlua->T, "puid");
9222 lua_pushinteger(hlua->T, e_server->safe.puid);
9223 lua_settable(hlua->T, -3);
9224 /* Add server rid */
9225 lua_pushstring(hlua->T, "rid");
9226 lua_pushinteger(hlua->T, e_server->safe.rid);
9227 lua_settable(hlua->T, -3);
9228 /* Add server proxy name */
9229 lua_pushstring(hlua->T, "proxy_name");
9230 lua_pushstring(hlua->T, e_server->safe.proxy_name);
9231 lua_settable(hlua->T, -3);
Aurelien DARRAGON55f84c72023-03-22 17:49:04 +01009232 /* Add server proxy uuid */
9233 lua_pushstring(hlua->T, "proxy_uuid");
9234 lua_pushinteger(hlua->T, e_server->safe.proxy_uuid);
9235 lua_settable(hlua->T, -3);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009236
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +02009237 /* special events, fetch additional info with explicit type casting */
9238 if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_STATE, event)) {
9239 struct event_hdl_cb_data_server_state *state = data;
9240 int it;
9241
9242 if (!lua_checkstack(hlua->T, 20))
9243 WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
9244
9245 /* state subclass */
9246 lua_pushstring(hlua->T, "state");
9247 lua_newtable(hlua->T);
9248
9249 lua_pushstring(hlua->T, "admin");
9250 lua_pushboolean(hlua->T, state->safe.type);
9251 lua_settable(hlua->T, -3);
9252
9253 /* is it because of a check ? */
9254 if (!state->safe.type &&
9255 (state->safe.op_st_chg.cause == SRV_OP_STCHGC_HEALTH ||
9256 state->safe.op_st_chg.cause == SRV_OP_STCHGC_AGENT)) {
9257 /* yes, provide check result */
9258 lua_pushstring(hlua->T, "check");
9259 lua_newtable(hlua->T);
9260 hlua_event_hdl_cb_push_event_checkres(hlua->T, &state->safe.op_st_chg.check);
9261 lua_settable(hlua->T, -3); /* check table */
9262 }
9263
9264 lua_pushstring(hlua->T, "cause");
9265 if (state->safe.type)
9266 lua_pushstring(hlua->T, srv_adm_st_chg_cause(state->safe.adm_st_chg.cause));
9267 else
9268 lua_pushstring(hlua->T, srv_op_st_chg_cause(state->safe.op_st_chg.cause));
9269 lua_settable(hlua->T, -3);
9270
9271 /* old_state, new_state */
9272 for (it = 0; it < 2; it++) {
9273 enum srv_state srv_state = (!it) ? state->safe.old_state : state->safe.new_state;
9274
9275 lua_pushstring(hlua->T, (!it) ? "old_state" : "new_state");
9276 switch (srv_state) {
9277 case SRV_ST_STOPPED:
9278 lua_pushstring(hlua->T, "STOPPED");
9279 break;
9280 case SRV_ST_STOPPING:
9281 lua_pushstring(hlua->T, "STOPPING");
9282 break;
9283 case SRV_ST_STARTING:
9284 lua_pushstring(hlua->T, "STARTING");
9285 break;
9286 case SRV_ST_RUNNING:
9287 lua_pushstring(hlua->T, "RUNNING");
9288 break;
9289 default:
9290 lua_pushnil(hlua->T);
9291 break;
9292 }
9293 lua_settable(hlua->T, -3);
9294 }
9295
9296 /* requeued */
9297 lua_pushstring(hlua->T, "requeued");
9298 lua_pushinteger(hlua->T, state->safe.requeued);
9299 lua_settable(hlua->T, -3);
9300
9301 lua_settable(hlua->T, -3); /* state table */
9302 }
Aurelien DARRAGON948dd3d2023-04-26 11:27:09 +02009303 else if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_ADMIN, event)) {
9304 struct event_hdl_cb_data_server_admin *admin = data;
9305 int it;
9306
9307 if (!lua_checkstack(hlua->T, 20))
9308 WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
9309
9310 /* admin subclass */
9311 lua_pushstring(hlua->T, "admin");
9312 lua_newtable(hlua->T);
9313
9314 lua_pushstring(hlua->T, "cause");
9315 lua_pushstring(hlua->T, srv_adm_st_chg_cause(admin->safe.cause));
9316 lua_settable(hlua->T, -3);
9317
9318 /* old_admin, new_admin */
9319 for (it = 0; it < 2; it++) {
9320 enum srv_admin srv_admin = (!it) ? admin->safe.old_admin : admin->safe.new_admin;
9321
9322 lua_pushstring(hlua->T, (!it) ? "old_admin" : "new_admin");
9323
9324 /* admin state matrix */
9325 lua_newtable(hlua->T);
9326
9327 lua_pushstring(hlua->T, "MAINT");
9328 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_MAINT);
9329 lua_settable(hlua->T, -3);
9330 lua_pushstring(hlua->T, "FMAINT");
9331 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_FMAINT);
9332 lua_settable(hlua->T, -3);
9333 lua_pushstring(hlua->T, "IMAINT");
9334 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_IMAINT);
9335 lua_settable(hlua->T, -3);
9336 lua_pushstring(hlua->T, "RMAINT");
9337 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_RMAINT);
9338 lua_settable(hlua->T, -3);
9339 lua_pushstring(hlua->T, "CMAINT");
9340 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_CMAINT);
9341 lua_settable(hlua->T, -3);
9342
9343 lua_pushstring(hlua->T, "DRAIN");
9344 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_DRAIN);
9345 lua_settable(hlua->T, -3);
9346 lua_pushstring(hlua->T, "FDRAIN");
9347 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_FDRAIN);
9348 lua_settable(hlua->T, -3);
9349 lua_pushstring(hlua->T, "IDRAIN");
9350 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_IDRAIN);
9351 lua_settable(hlua->T, -3);
9352
9353 lua_settable(hlua->T, -3); /* matrix table */
9354 }
9355 /* requeued */
9356 lua_pushstring(hlua->T, "requeued");
9357 lua_pushinteger(hlua->T, admin->safe.requeued);
9358 lua_settable(hlua->T, -3);
9359
9360 lua_settable(hlua->T, -3); /* admin table */
9361 }
Aurelien DARRAGON0bd53b22023-03-30 15:53:33 +02009362 else if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_CHECK, event)) {
9363 struct event_hdl_cb_data_server_check *check = data;
9364
9365 if (!lua_checkstack(hlua->T, 20))
9366 WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
9367
9368 /* check subclass */
9369 lua_pushstring(hlua->T, "check");
9370 lua_newtable(hlua->T);
9371
9372 /* check result snapshot */
9373 hlua_event_hdl_cb_push_event_checkres(hlua->T, &check->safe.res);
9374
9375 lua_settable(hlua->T, -3); /* check table */
9376 }
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +02009377
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009378 /* attempt to provide reference server object
9379 * (if it wasn't removed yet, SERVER_DEL will never succeed here)
9380 */
Aurelien DARRAGON3d9bf4e2023-03-22 17:46:12 +01009381 px = proxy_find_by_id(e_server->safe.proxy_uuid, PR_CAP_BE, 0);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009382 BUG_ON(!px);
9383 server = findserver_unique_id(px, e_server->safe.puid, e_server->safe.rid);
9384 if (server) {
9385 lua_pushstring(hlua->T, "reference");
9386 hlua_fcn_new_server(hlua->T, server);
9387 lua_settable(hlua->T, -3);
9388 }
9389 }
9390 /* sub mgmt */
9391 hlua->nargs += 1;
9392 hlua_fcn_new_event_sub(hlua->T, hlua_sub->sub);
Aurelien DARRAGON096b3832023-04-20 11:32:46 +02009393
9394 /* when? */
9395 hlua->nargs += 1;
9396 lua_pushinteger(hlua->T, e->when.tv_sec);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009397}
9398
9399/* events runner: if there's an ongoing hlua event handling process, finish it
9400 * then, check if there are new events waiting to be processed
9401 * (events are processed sequentially)
9402 *
9403 * We have a safety measure to warn/guard if the event queue is growing up
9404 * too much due to many events being generated and lua handler is unable to
9405 * keep up the pace (e.g.: when the event queue grows past 100 unconsumed events).
9406 * TODO: make it tunable
9407 */
9408static struct task *hlua_event_runner(struct task *task, void *context, unsigned int state)
9409{
9410 struct hlua_event_sub *hlua_sub = context;
9411 struct event_hdl_async_event *event;
9412 const char *error = NULL;
9413
9414 if (!hlua_sub->paused && event_hdl_async_equeue_size(&hlua_sub->equeue) > 100) {
Aurelien DARRAGON7428ada2023-05-15 18:46:44 +02009415 const char *trace = NULL;
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009416
9417 /* We reached the limit of pending events in the queue: we should
9418 * warn the user, and temporarily pause the subscription to give a chance
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009419 * to the handler to catch up? (it also prevents resource shortage since
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009420 * the queue could grow indefinitely otherwise)
9421 * TODO: find a way to inform the handler that it missed some events
9422 * (example: stats within the subscription in event_hdl api exposed via lua api?)
9423 *
9424 * Nonetheless, reaching this limit means that the handler is not fast enough
9425 * and/or that it subscribed to events that happen too frequently and did not
9426 * expect it. This could come from an inadequate design in the user's script.
9427 */
9428 event_hdl_pause(hlua_sub->sub);
9429 hlua_sub->paused = 1;
9430
Aurelien DARRAGON7428ada2023-05-15 18:46:44 +02009431 if (SET_SAFE_LJMP(hlua_sub->hlua)) {
9432 /* The following Lua call may fail. */
9433 trace = hlua_traceback(hlua_sub->hlua->T, ", ");
9434 /* At this point the execution is safe. */
9435 RESET_SAFE_LJMP(hlua_sub->hlua);
9436 } else {
9437 /* Lua error was raised while fetching lua trace from current ctx */
9438 SEND_ERR(NULL, "Lua event_hdl: unexpected error (memory failure?).\n");
9439 }
9440 ha_warning("Lua event_hdl: pausing the subscription because the handler fails "
9441 "to keep up the pace (%u unconsumed events) from %s.\n",
9442 event_hdl_async_equeue_size(&hlua_sub->equeue),
9443 (trace) ? trace : "[unknown]");
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009444 }
9445
9446 if (HLUA_IS_RUNNING(hlua_sub->hlua)) {
9447 /* ongoing hlua event handler, resume it */
9448 hlua_event_handler(hlua_sub->hlua);
9449 } else if ((event = event_hdl_async_equeue_pop(&hlua_sub->equeue))) { /* check for new events */
9450 if (event_hdl_sub_type_equal(event->type, EVENT_HDL_SUB_END)) {
9451 /* ending event: no more events to come */
9452 event_hdl_async_free_event(event);
9453 task_destroy(task);
9454 hlua_event_subscription_destroy(hlua_sub);
9455 return NULL;
9456 }
9457 /* new event: start processing it */
9458
9459 /* The following Lua calls can fail. */
9460 if (!SET_SAFE_LJMP(hlua_sub->hlua)) {
9461 if (lua_type(hlua_sub->hlua->T, -1) == LUA_TSTRING)
9462 error = lua_tostring(hlua_sub->hlua->T, -1);
9463 else
9464 error = "critical error";
9465 ha_alert("Lua event_hdl: %s.\n", error);
9466 goto skip_event;
9467 }
9468
9469 /* Check stack available size. */
9470 if (!lua_checkstack(hlua_sub->hlua->T, 5)) {
9471 ha_alert("Lua event_hdl: full stack.\n");
9472 RESET_SAFE_LJMP(hlua_sub->hlua);
9473 goto skip_event;
9474 }
9475
9476 /* Restore the function in the stack. */
9477 hlua_pushref(hlua_sub->hlua->T, hlua_sub->fcn_ref);
9478
9479 /* push args */
9480 hlua_sub->hlua->nargs = 0;
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009481 MAY_LJMP(hlua_event_hdl_cb_push_args(hlua_sub, event));
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009482
9483 /* At this point the execution is safe. */
9484 RESET_SAFE_LJMP(hlua_sub->hlua);
9485
9486 /* At this point the event was successfully translated into hlua ctx,
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009487 * or hlua error occurred, so we can safely discard it
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009488 */
9489 event_hdl_async_free_event(event);
9490 event = NULL;
9491
9492 hlua_event_handler(hlua_sub->hlua);
9493 skip_event:
9494 if (event)
9495 event_hdl_async_free_event(event);
9496
9497 }
9498
9499 if (!HLUA_IS_RUNNING(hlua_sub->hlua)) {
9500 /* we just finished the processing of one event..
9501 * check for new events before becoming idle
9502 */
9503 if (!event_hdl_async_equeue_isempty(&hlua_sub->equeue)) {
9504 /* more events to process, make sure the task
9505 * will be resumed ASAP to process pending events
9506 */
9507 task_wakeup(task, TASK_WOKEN_OTHER);
9508 }
9509 else if (hlua_sub->paused) {
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009510 /* empty queue, the handler caught up: resume the subscription */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009511 event_hdl_resume(hlua_sub->sub);
9512 hlua_sub->paused = 0;
9513 }
9514 }
9515
9516 return task;
9517}
9518
9519/* Must be called directly under lua protected/safe environment
9520 * (not from external callback)
9521 * <fcn_ref> should NOT be dropped after the function successfully returns:
9522 * it will be done automatically in hlua_event_subscription_destroy() when the
9523 * subscription ends.
9524 *
9525 * Returns the new subscription on success and NULL on failure (memory error)
9526 */
9527static struct event_hdl_sub *hlua_event_subscribe(event_hdl_sub_list *list, struct event_hdl_sub_type e_type,
9528 int state_id, int fcn_ref)
9529{
9530 struct hlua_event_sub *hlua_sub;
9531 struct task *task = NULL;
9532
9533 hlua_sub = pool_alloc(pool_head_hlua_event_sub);
9534 if (!hlua_sub)
9535 goto mem_error;
9536 hlua_sub->task = NULL;
9537 hlua_sub->hlua = NULL;
9538 hlua_sub->paused = 0;
9539 if ((task = task_new_here()) == NULL) {
9540 ha_alert("out of memory while allocating hlua event task");
9541 goto mem_error;
9542 }
9543 task->process = hlua_event_runner;
9544 task->context = hlua_sub;
9545 event_hdl_async_equeue_init(&hlua_sub->equeue);
9546 hlua_sub->task = task;
9547 hlua_sub->fcn_ref = fcn_ref;
9548 hlua_sub->state_id = state_id;
9549 hlua_sub->hlua = pool_alloc(pool_head_hlua);
9550 if (!hlua_sub->hlua)
9551 goto mem_error;
9552 HLUA_INIT(hlua_sub->hlua);
9553 if (!hlua_ctx_init(hlua_sub->hlua, hlua_sub->state_id, task))
9554 goto mem_error;
9555
9556 hlua_sub->sub = event_hdl_subscribe_ptr(list, e_type,
9557 EVENT_HDL_ASYNC_TASK(&hlua_sub->equeue,
9558 task,
9559 hlua_sub,
9560 NULL));
9561 if (!hlua_sub->sub)
9562 goto mem_error;
9563
9564 return hlua_sub->sub; /* returns pointer to event_hdl_sub struct */
9565
9566 mem_error:
9567 if (hlua_sub) {
Tim Duesterhusfe83f582023-04-22 17:47:34 +02009568 task_destroy(hlua_sub->task);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009569 if (hlua_sub->hlua)
9570 hlua_ctx_destroy(hlua_sub->hlua);
9571 pool_free(pool_head_hlua_event_sub, hlua_sub);
9572 }
9573
9574 return NULL;
9575}
9576
9577/* looks for an array of strings referring to a composition of event_hdl subscription
9578 * types at <index> in <L> stack
9579 */
9580__LJMP static struct event_hdl_sub_type hlua_check_event_sub_types(lua_State *L, int index)
9581{
9582 struct event_hdl_sub_type subscriptions;
9583 const char *msg;
9584
9585 if (lua_type(L, index) != LUA_TTABLE) {
9586 msg = lua_pushfstring(L, "table of strings expected, got %s", luaL_typename(L, index));
9587 luaL_argerror(L, index, msg);
9588 }
9589
9590 subscriptions = EVENT_HDL_SUB_NONE;
9591
9592 /* browse the argument as an array. */
9593 lua_pushnil(L);
9594 while (lua_next(L, index) != 0) {
9595 if (lua_type(L, -1) != LUA_TSTRING) {
9596 msg = lua_pushfstring(L, "table of strings expected, got %s", luaL_typename(L, index));
9597 luaL_argerror(L, index, msg);
9598 }
9599
9600 if (event_hdl_sub_type_equal(EVENT_HDL_SUB_NONE, event_hdl_string_to_sub_type(lua_tostring(L, -1)))) {
9601 msg = lua_pushfstring(L, "'%s' event type is unknown", lua_tostring(L, -1));
9602 luaL_argerror(L, index, msg);
9603 }
9604
9605 /* perform subscriptions |= current sub */
9606 subscriptions = event_hdl_sub_type_add(subscriptions, event_hdl_string_to_sub_type(lua_tostring(L, -1)));
9607
9608 /* pop the current value. */
9609 lua_pop(L, 1);
9610 }
9611
9612 return subscriptions;
9613}
9614
9615/* Wrapper for hlua_fcn_new_event_sub(): catch errors raised by
9616 * the function to prevent LJMP
9617 *
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009618 * If no error occurred, the function returns 1, else it returns 0 and
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009619 * the error message is pushed at the top of the stack
9620 */
9621__LJMP static int _hlua_new_event_sub_safe(lua_State *L)
9622{
9623 struct event_hdl_sub *sub = lua_touserdata(L, 1);
9624
9625 /* this function may raise errors */
9626 return MAY_LJMP(hlua_fcn_new_event_sub(L, sub));
9627}
9628static int hlua_new_event_sub_safe(lua_State *L, struct event_hdl_sub *sub)
9629{
9630 if (!lua_checkstack(L, 2))
9631 return 0;
9632 lua_pushcfunction(L, _hlua_new_event_sub_safe);
9633 lua_pushlightuserdata(L, sub);
9634 switch (lua_pcall(L, 1, 1, 0)) {
9635 case LUA_OK:
9636 return 1;
9637 default:
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009638 /* error was caught */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009639 return 0;
9640 }
9641}
9642
9643/* This function is a LUA helper used for registering lua event callbacks.
9644 * It expects an event subscription array and the function to be executed
9645 * when subscribed events occur (stack arguments).
9646 * It can be called from the "init" section, "post init" or during the runtime.
9647 *
9648 * <sub_list> is the subscription list where the subscription will be attempted
9649 *
9650 * Pushes the newly allocated subscription on the stack on success
9651 */
9652__LJMP int hlua_event_sub(lua_State *L, event_hdl_sub_list *sub_list)
9653{
9654 struct hlua *hlua;
9655 struct event_hdl_sub *sub;
9656 struct event_hdl_sub_type subscriptions;
9657 int fcn_ref;
9658 int state_id;
9659
9660 MAY_LJMP(check_args(L, 2, "event_sub"));
9661
9662 /* Get the reference state */
9663 hlua = hlua_gethlua(L);
9664 if (hlua)
9665 /* we are in runtime processing, any thread may subscribe to events:
9666 * subscription events will be handled by the thread who performed
9667 * the registration.
9668 */
9669 state_id = hlua->state_id;
9670 else {
9671 /* we are in initialization mode, only thread 0 (actual calling thread)
9672 * may subscribe to events to prevent the same handler (from different lua
9673 * stacks) from being registered multiple times
9674 *
9675 * hlua_state_id == 0: monostack (lua-load)
9676 * hlua_state_id > 0: hlua_state_id=tid+1, multi-stack (lua-load-per-thread)
9677 * (thus if hlua_state_id > 1, it means we are not in primary thread ctx)
9678 */
9679 if (hlua_state_id > 1)
9680 return 0; /* skip registration */
9681 state_id = hlua_state_id;
9682 }
9683
9684 /* First argument : event subscriptions. */
9685 subscriptions = MAY_LJMP(hlua_check_event_sub_types(L, 1));
9686
9687 if (event_hdl_sub_type_equal(subscriptions, EVENT_HDL_SUB_NONE)) {
9688 WILL_LJMP(luaL_error(L, "event_sub: no valid event types were provided"));
9689 return 0; /* Never reached */
9690 }
9691
9692 /* Second argument : lua function. */
9693 fcn_ref = MAY_LJMP(hlua_checkfunction(L, 2));
9694
9695 /* try to subscribe */
9696 sub = hlua_event_subscribe(sub_list, subscriptions, state_id, fcn_ref);
9697 if (!sub) {
9698 hlua_unref(L, fcn_ref);
9699 WILL_LJMP(luaL_error(L, "event_sub: lua out of memory error"));
9700 return 0; /* Never reached */
9701 }
9702
9703 /* push the subscription to the stack
9704 *
9705 * Here we use the safe function so that lua errors will be
9706 * handled explicitly to prevent 'sub' from being lost
9707 */
9708 if (!hlua_new_event_sub_safe(L, sub)) {
9709 /* Some events could already be pending in the handler's queue.
9710 * However it is wiser to cancel the subscription since we are unable to
9711 * provide a valid reference to it.
9712 * Pending events will be delivered (unless lua keeps raising errors).
9713 */
9714 event_hdl_unsubscribe(sub); /* cancel the subscription */
9715 WILL_LJMP(luaL_error(L, "event_sub: cannot push the subscription (%s)", lua_tostring(L, -1)));
9716 return 0; /* Never reached */
9717 }
9718 event_hdl_drop(sub); /* sub has been duplicated, discard old ref */
9719
9720 return 1;
9721}
9722
9723/* This function is a LUA wrapper used for registering global lua event callbacks
9724 * The new subscription is pushed onto the stack on success
9725 * Returns the number of arguments pushed to the stack (1 for success)
9726 */
9727__LJMP static int hlua_event_global_sub(lua_State *L)
9728{
9729 /* NULL <sub_list> = global subscription list */
9730 return MAY_LJMP(hlua_event_sub(L, NULL));
9731}
9732
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009733/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
9734 * doesn't allow "yield" functions because the HAProxy engine cannot
9735 * resume converters.
9736 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02009737static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009738{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009739 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02009740 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009741 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009742
Willy Tarreaube508f12016-03-10 11:47:01 +01009743 if (!stream)
9744 return 0;
9745
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +02009746 if (!hlua_stream_ctx_prepare(stream, fcn_ref_to_stack_id(fcn))) {
9747 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
9748 return 0;
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009749 }
9750
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009751 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009752 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009753
9754 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009755 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009756 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
9757 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009758 else
9759 error = "critical error";
9760 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009761 return 0;
9762 }
9763
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009764 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009765 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009766 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009767 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009768 return 0;
9769 }
9770
9771 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009772 hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009773
9774 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009775 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009776 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009777 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009778 return 0;
9779 }
Aurelien DARRAGON41217722023-05-17 10:44:47 +02009780 MAY_LJMP(hlua_smp2lua(stream->hlua->T, smp));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009781 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009782
9783 /* push keywords in the stack. */
9784 if (arg_p) {
9785 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009786 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009787 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009788 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009789 return 0;
9790 }
Aurelien DARRAGONe5c048a2023-05-17 10:51:50 +02009791 MAY_LJMP(hlua_arg2lua(stream->hlua->T, arg_p));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009792 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009793 }
9794 }
9795
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009796 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01009797 hlua_timer_init(&stream->hlua->timer, hlua_timeout_session);
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009798
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009799 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009800 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009801 }
9802
9803 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009804 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009805 /* finished. */
9806 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02009807 /* If the stack is empty, the function fails. */
9808 if (lua_gettop(stream->hlua->T) <= 0)
9809 return 0;
9810
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009811 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009812 hlua_lua2smp(stream->hlua->T, -1, smp);
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02009813 /* dup the smp before popping the related lua value and
9814 * returning it to haproxy
9815 */
9816 smp_dup(smp);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009817 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009818 return 1;
9819
9820 /* yield. */
9821 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009822 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009823 return 0;
9824
9825 /* finished with error. */
9826 case HLUA_E_ERRMSG:
9827 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009828 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009829 fcn->name, lua_tostring(stream->hlua->T, -1));
9830 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009831 return 0;
9832
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009833 case HLUA_E_ETMOUT:
9834 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
9835 return 0;
9836
9837 case HLUA_E_NOMEM:
9838 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
9839 return 0;
9840
9841 case HLUA_E_YIELD:
9842 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
9843 return 0;
9844
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009845 case HLUA_E_ERR:
9846 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009847 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01009848 __fallthrough;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009849
9850 default:
9851 return 0;
9852 }
9853}
9854
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009855/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
9856 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01009857 * resume sample-fetches. This function will be called by the sample
9858 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009859 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02009860static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
9861 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009862{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009863 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02009864 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009865 const char *error;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02009866 unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009867
Willy Tarreaube508f12016-03-10 11:47:01 +01009868 if (!stream)
9869 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01009870
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +02009871 if (!hlua_stream_ctx_prepare(stream, fcn_ref_to_stack_id(fcn))) {
9872 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
9873 return 0;
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009874 }
9875
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009876 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009877 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009878
9879 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009880 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009881 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
9882 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009883 else
9884 error = "critical error";
9885 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009886 return 0;
9887 }
9888
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009889 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009890 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009891 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009892 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009893 return 0;
9894 }
9895
9896 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009897 hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009898
9899 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02009900 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009901 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009902 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009903 return 0;
9904 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009905 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009906
9907 /* push keywords in the stack. */
9908 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
9909 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009910 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009911 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009912 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009913 return 0;
9914 }
Aurelien DARRAGONe5c048a2023-05-17 10:51:50 +02009915 MAY_LJMP(hlua_arg2lua(stream->hlua->T, arg_p));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009916 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009917 }
9918
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009919 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01009920 hlua_timer_init(&stream->hlua->timer, hlua_timeout_session);
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009921
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009922 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009923 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009924 }
9925
9926 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009927 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009928 /* finished. */
9929 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02009930 /* If the stack is empty, the function fails. */
9931 if (lua_gettop(stream->hlua->T) <= 0)
9932 return 0;
9933
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009934 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009935 hlua_lua2smp(stream->hlua->T, -1, smp);
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02009936 /* dup the smp before popping the related lua value and
9937 * returning it to haproxy
9938 */
9939 smp_dup(smp);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009940 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009941
9942 /* Set the end of execution flag. */
9943 smp->flags &= ~SMP_F_MAY_CHANGE;
9944 return 1;
9945
9946 /* yield. */
9947 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009948 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009949 return 0;
9950
9951 /* finished with error. */
9952 case HLUA_E_ERRMSG:
9953 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009954 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009955 fcn->name, lua_tostring(stream->hlua->T, -1));
9956 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009957 return 0;
9958
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009959 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009960 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
9961 return 0;
9962
9963 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009964 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
9965 return 0;
9966
9967 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009968 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
9969 return 0;
9970
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009971 case HLUA_E_ERR:
9972 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009973 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01009974 __fallthrough;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009975
9976 default:
9977 return 0;
9978 }
9979}
9980
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009981/* This function is an LUA binding used for registering
9982 * "sample-conv" functions. It expects a converter name used
9983 * in the haproxy configuration file, and an LUA function.
9984 */
9985__LJMP static int hlua_register_converters(lua_State *L)
9986{
9987 struct sample_conv_kw_list *sck;
9988 const char *name;
9989 int ref;
9990 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02009991 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009992 struct sample_conv *sc;
9993 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009994
9995 MAY_LJMP(check_args(L, 2, "register_converters"));
9996
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01009997 if (hlua_gethlua(L)) {
9998 /* runtime processing */
9999 WILL_LJMP(luaL_error(L, "register_converters: not available outside of body context"));
10000 }
10001
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010002 /* First argument : converter name. */
10003 name = MAY_LJMP(luaL_checkstring(L, 1));
10004
10005 /* Second argument : lua function. */
10006 ref = MAY_LJMP(hlua_checkfunction(L, 2));
10007
Thierry Fournierf67442e2020-11-28 20:41:07 +010010008 /* Check if the converter is already registered */
10009 trash = get_trash_chunk();
10010 chunk_printf(trash, "lua.%s", name);
10011 sc = find_sample_conv(trash->area, trash->data);
10012 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010013 fcn = sc->private;
10014 if (fcn->function_ref[hlua_state_id] != -1) {
10015 ha_warning("Trying to register converter 'lua.%s' more than once. "
10016 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010017 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010018 }
10019 fcn->function_ref[hlua_state_id] = ref;
10020 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010021 }
10022
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010023 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010024 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010025 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +020010026 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010027 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010028 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +020010029 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010030
10031 /* Fill fcn. */
10032 fcn->name = strdup(name);
10033 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +020010034 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010035 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010036
10037 /* List head */
10038 sck->list.n = sck->list.p = NULL;
10039
10040 /* converter keyword. */
10041 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010042 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010043 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +020010044 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010045
10046 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
10047 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +010010048 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 +010010049 sck->kw[0].val_args = NULL;
10050 sck->kw[0].in_type = SMP_T_STR;
10051 sck->kw[0].out_type = SMP_T_STR;
10052 sck->kw[0].private = fcn;
10053
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010054 /* Register this new converter */
10055 sample_register_convs(sck);
10056
10057 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +020010058
10059 alloc_error:
10060 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010061 hlua_unref(L, ref);
Christopher Fauletaa224302021-04-12 14:08:21 +020010062 ha_free(&sck);
10063 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10064 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010065}
10066
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010067/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010068 * "sample-fetch" functions. It expects a converter name used
10069 * in the haproxy configuration file, and an LUA function.
10070 */
10071__LJMP static int hlua_register_fetches(lua_State *L)
10072{
10073 const char *name;
10074 int ref;
10075 int len;
10076 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +020010077 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010078 struct sample_fetch *sf;
10079 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010080
10081 MAY_LJMP(check_args(L, 2, "register_fetches"));
10082
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010010083 if (hlua_gethlua(L)) {
10084 /* runtime processing */
10085 WILL_LJMP(luaL_error(L, "register_fetches: not available outside of body context"));
10086 }
10087
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010088 /* First argument : sample-fetch name. */
10089 name = MAY_LJMP(luaL_checkstring(L, 1));
10090
10091 /* Second argument : lua function. */
10092 ref = MAY_LJMP(hlua_checkfunction(L, 2));
10093
Thierry Fournierf67442e2020-11-28 20:41:07 +010010094 /* Check if the sample-fetch is already registered */
10095 trash = get_trash_chunk();
10096 chunk_printf(trash, "lua.%s", name);
10097 sf = find_sample_fetch(trash->area, trash->data);
10098 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010099 fcn = sf->private;
10100 if (fcn->function_ref[hlua_state_id] != -1) {
10101 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
10102 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010103 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010104 }
10105 fcn->function_ref[hlua_state_id] = ref;
10106 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010107 }
10108
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010109 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010110 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010111 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +020010112 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010113 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010114 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +020010115 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010116
10117 /* Fill fcn. */
10118 fcn->name = strdup(name);
10119 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +020010120 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010121 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010122
10123 /* List head */
10124 sfk->list.n = sfk->list.p = NULL;
10125
10126 /* sample-fetch keyword. */
10127 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010128 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010129 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +020010130 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010131
10132 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
10133 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +010010134 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 +010010135 sfk->kw[0].val_args = NULL;
10136 sfk->kw[0].out_type = SMP_T_STR;
10137 sfk->kw[0].use = SMP_USE_HTTP_ANY;
10138 sfk->kw[0].val = 0;
10139 sfk->kw[0].private = fcn;
10140
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010141 /* Register this new fetch. */
10142 sample_register_fetches(sfk);
10143
10144 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +020010145
10146 alloc_error:
10147 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010148 hlua_unref(L, ref);
Christopher Faulet2567f182021-04-12 14:11:50 +020010149 ha_free(&sfk);
10150 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10151 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010152}
10153
Christopher Faulet501465d2020-02-26 14:54:16 +010010154/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010155 */
Christopher Faulet501465d2020-02-26 14:54:16 +010010156__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010157{
Thierry Fournier4234dbd2020-11-28 13:18:23 +010010158 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010159 unsigned int delay;
Aurelien DARRAGON2a9764b2023-04-04 18:41:04 +020010160 int wakeup_ms; // tick value
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010161
Thierry Fournier4234dbd2020-11-28 13:18:23 +010010162 /* Get hlua struct, or NULL if we execute from main lua state */
10163 hlua = hlua_gethlua(L);
10164 if (!hlua) {
10165 return 0;
10166 }
10167
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010168 MAY_LJMP(check_args(L, 1, "wake_time"));
10169
10170 delay = MAY_LJMP(luaL_checkinteger(L, 1));
10171 wakeup_ms = tick_add(now_ms, delay);
10172 hlua->wake_time = wakeup_ms;
10173 return 0;
10174}
10175
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010176/* This function is a wrapper to execute each LUA function declared as an action
10177 * wrapper during the initialisation period. This function may return any
10178 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
10179 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
10180 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010181 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010182static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +020010183 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010184{
10185 char **arg;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +020010186 unsigned int hflags = HLUA_TXN_ACT_CTX;
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010187 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +010010188 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010189
10190 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +010010191 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
10192 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
10193 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
10194 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010195 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010196 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010197 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010198 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010199
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +020010200 if (!hlua_stream_ctx_prepare(s, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn))) {
10201 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
10202 rule->arg.hlua_rule->fcn->name);
10203 goto end;
Thierry FOURNIER05ac4242015-02-27 18:37:27 +010010204 }
10205
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010206 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010207 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010208
10209 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010210 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010211 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
10212 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +010010213 else
10214 error = "critical error";
10215 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010216 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010217 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010218 }
10219
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010220 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010221 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010222 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010223 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010224 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010225 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010226 }
10227
10228 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010229 hlua_pushref(s->hlua->T, rule->arg.hlua_rule->fcn->function_ref[s->hlua->state_id]);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010230
Willy Tarreau87b09662015-04-03 00:22:06 +020010231 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +020010232 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010233 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010234 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010235 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010236 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010237 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010238 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010239
10240 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010241 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010242 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010243 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010244 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010245 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010246 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010247 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010248 lua_pushstring(s->hlua->T, *arg);
10249 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010250 }
10251
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010252 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010253 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010254
Thierry FOURNIERbd413492015-03-03 16:52:26 +010010255 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010010256 hlua_timer_init(&s->hlua->timer, hlua_timeout_session);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010257 }
10258
10259 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +010010260 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010261 /* finished. */
10262 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010263 /* Catch the return value */
10264 if (lua_gettop(s->hlua->T) > 0)
10265 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010266
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010267 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +020010268 if (act_ret == ACT_RET_YIELD) {
10269 if (flags & ACT_OPT_FINAL)
10270 goto err_yield;
10271
Christopher Faulet8f587ea2020-07-28 12:01:55 +020010272 if (dir == SMP_OPT_DIR_REQ)
10273 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
10274 s->hlua->wake_time);
10275 else
10276 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
10277 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010278 }
10279 goto end;
10280
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010281 /* yield. */
10282 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +010010283 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +020010284 if (dir == SMP_OPT_DIR_REQ)
10285 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
10286 s->hlua->wake_time);
10287 else
10288 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
10289 s->hlua->wake_time);
10290
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010291 /* Some actions can be wake up when a "write" event
10292 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010293 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010294 */
Christopher Faulet51fa3582019-07-26 14:54:52 +020010295 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010010296 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010297 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010010298 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010299 act_ret = ACT_RET_YIELD;
10300 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010301
10302 /* finished with error. */
10303 case HLUA_E_ERRMSG:
10304 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010305 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010306 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010307 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010308 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010309
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010310 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +010010311 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010312 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010313
10314 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +010010315 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010316 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010317
10318 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +020010319 err_yield:
10320 act_ret = ACT_RET_CONT;
Aurelien DARRAGONcf5b75e2023-08-31 21:45:21 +020010321 SEND_ERR(px, "Lua function '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010322 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010323 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010324
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010325 case HLUA_E_ERR:
10326 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010327 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010328 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010329
10330 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010331 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010332 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010333
10334 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +020010335 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +020010336 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010337 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010338}
10339
Willy Tarreau144f84a2021-03-02 16:09:26 +010010340struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010341{
Olivier Houchard9f6af332018-05-25 14:04:04 +020010342 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010343
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010344 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +020010345 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +020010346 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010347}
10348
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010349static int hlua_applet_tcp_init(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010350{
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010351 struct hlua_tcp_ctx *tcp_ctx = applet_reserve_svcctx(ctx, sizeof(*tcp_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +020010352 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010353 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010354 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010355 struct task *task;
10356 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +010010357 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010358
Willy Tarreaubafbe012017-11-24 17:34:44 +010010359 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010360 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010361 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010362 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010363 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010364 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010365 HLUA_INIT(hlua);
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010366 tcp_ctx->hlua = hlua;
10367 tcp_ctx->flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010368
10369 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +020010370 task = task_new_here();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010371 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010372 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010373 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010374 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010375 }
10376 task->nice = 0;
10377 task->context = ctx;
10378 task->process = hlua_applet_wakeup;
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010379 tcp_ctx->task = task;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010380
10381 /* In the execution wrappers linked with a stream, the
10382 * Lua context can be not initialized. This behavior
10383 * permits to save performances because a systematic
10384 * Lua initialization cause 5% performances loss.
10385 */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010010386 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010387 SEND_ERR(strm->be, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010388 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010389 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010390 }
10391
10392 /* Set timeout according with the applet configuration. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010010393 hlua_timer_init(&hlua->timer, ctx->applet->timeout);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010394
10395 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010396 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +010010397 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10398 error = lua_tostring(hlua->T, -1);
10399 else
10400 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010401 SEND_ERR(strm->be, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010402 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +020010403 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010404 }
10405
10406 /* Check stack available size. */
10407 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010408 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010409 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010410 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010411 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010412 }
10413
10414 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010415 hlua_pushref(hlua->T, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010416
10417 /* Create and and push object stream in the stack. */
10418 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010419 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010420 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010421 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010422 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010423 }
10424 hlua->nargs = 1;
10425
10426 /* push keywords in the stack. */
10427 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
10428 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010429 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010430 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010431 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010432 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010433 }
10434 lua_pushstring(hlua->T, *arg);
10435 hlua->nargs++;
10436 }
10437
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010438 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010439
10440 /* Wakeup the applet ASAP. */
Willy Tarreau90e8b452022-05-25 18:21:43 +020010441 applet_need_more_data(ctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +020010442 applet_have_more_data(ctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010443
Christopher Fauletc9929382022-05-12 11:52:27 +020010444 return 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010445}
10446
Willy Tarreau60409db2019-08-21 14:14:50 +020010447void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010448{
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010449 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010450 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010451 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010452 struct act_rule *rule = ctx->rule;
10453 struct proxy *px = strm->be;
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010454 struct hlua *hlua = tcp_ctx->hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010455
Christopher Faulet31572222023-03-31 11:13:48 +020010456 if (unlikely(se_fl_test(ctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
10457 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010458
Christopher Faulet31572222023-03-31 11:13:48 +020010459 /* The applet execution is already done. */
10460 if (tcp_ctx->flags & APPLET_DONE)
10461 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010462
10463 /* Execute the function. */
10464 switch (hlua_ctx_resume(hlua, 1)) {
10465 /* finished. */
10466 case HLUA_E_OK:
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010467 tcp_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +020010468 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
10469 break;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010470
10471 /* yield. */
10472 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +010010473 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010474 task_schedule(tcp_ctx->task, hlua->wake_time);
Christopher Faulet31572222023-03-31 11:13:48 +020010475 break;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010476
10477 /* finished with error. */
10478 case HLUA_E_ERRMSG:
10479 /* Display log. */
10480 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010481 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010482 lua_pop(hlua->T, 1);
10483 goto error;
10484
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010485 case HLUA_E_ETMOUT:
10486 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010487 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010488 goto error;
10489
10490 case HLUA_E_NOMEM:
10491 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010492 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010493 goto error;
10494
10495 case HLUA_E_YIELD: /* unexpected */
10496 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010497 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010498 goto error;
10499
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010500 case HLUA_E_ERR:
10501 /* Display log. */
10502 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010503 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010504 goto error;
10505
10506 default:
10507 goto error;
10508 }
10509
Christopher Faulet31572222023-03-31 11:13:48 +020010510out:
10511 /* eat the whole request */
10512 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
10513 return;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010514
Christopher Faulet31572222023-03-31 11:13:48 +020010515error:
10516 se_fl_set(ctx->sedesc, SE_FL_ERROR);
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010517 tcp_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +020010518 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010519}
10520
10521static void hlua_applet_tcp_release(struct appctx *ctx)
10522{
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010523 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
10524
10525 task_destroy(tcp_ctx->task);
10526 tcp_ctx->task = NULL;
10527 hlua_ctx_destroy(tcp_ctx->hlua);
10528 tcp_ctx->hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010529}
10530
Christopher Fauletc9929382022-05-12 11:52:27 +020010531/* The function returns 0 if the initialisation is complete or -1 if
10532 * an errors occurs. It also reserves the appctx for an hlua_http_ctx.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010533 */
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010534static int hlua_applet_http_init(struct appctx *ctx)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010535{
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010536 struct hlua_http_ctx *http_ctx = applet_reserve_svcctx(ctx, sizeof(*http_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +020010537 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010538 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010539 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010540 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010541 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010542 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +010010543 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010544
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010545 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +010010546 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010547 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010548 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010549 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010550 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010551 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010552 HLUA_INIT(hlua);
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010553 http_ctx->hlua = hlua;
10554 http_ctx->left_bytes = -1;
10555 http_ctx->flags = 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010556
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +010010557 if (txn->req.flags & HTTP_MSGF_VER_11)
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010558 http_ctx->flags |= APPLET_HTTP11;
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +010010559
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010560 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +020010561 task = task_new_here();
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010562 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010563 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010564 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010565 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010566 }
10567 task->nice = 0;
10568 task->context = ctx;
10569 task->process = hlua_applet_wakeup;
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010570 http_ctx->task = task;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010571
10572 /* In the execution wrappers linked with a stream, the
10573 * Lua context can be not initialized. This behavior
10574 * permits to save performances because a systematic
10575 * Lua initialization cause 5% performances loss.
10576 */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010010577 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010578 SEND_ERR(strm->be, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010579 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010580 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010581 }
10582
10583 /* Set timeout according with the applet configuration. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010010584 hlua_timer_init(&hlua->timer, ctx->applet->timeout);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010585
10586 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010587 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +010010588 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10589 error = lua_tostring(hlua->T, -1);
10590 else
10591 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010592 SEND_ERR(strm->be, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010593 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +020010594 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010595 }
10596
10597 /* Check stack available size. */
10598 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010599 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010600 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010601 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010602 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010603 }
10604
10605 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010606 hlua_pushref(hlua->T, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010607
10608 /* Create and and push object stream in the stack. */
10609 if (!hlua_applet_http_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010610 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010611 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010612 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010613 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010614 }
10615 hlua->nargs = 1;
10616
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010617 /* push keywords in the stack. */
10618 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
10619 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010620 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010621 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010622 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010623 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010624 }
10625 lua_pushstring(hlua->T, *arg);
10626 hlua->nargs++;
10627 }
10628
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010629 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010630
10631 /* Wakeup the applet when data is ready for read. */
Willy Tarreau90e8b452022-05-25 18:21:43 +020010632 applet_need_more_data(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010633
Christopher Fauletc9929382022-05-12 11:52:27 +020010634 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010635}
10636
Willy Tarreau60409db2019-08-21 14:14:50 +020010637void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010638{
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010639 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010640 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010641 struct stream *strm = __sc_strm(sc);
10642 struct channel *req = sc_oc(sc);
10643 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010644 struct act_rule *rule = ctx->rule;
10645 struct proxy *px = strm->be;
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010646 struct hlua *hlua = http_ctx->hlua;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010647 struct htx *req_htx, *res_htx;
10648
10649 res_htx = htx_from_buf(&res->buf);
10650
Christopher Faulet31572222023-03-31 11:13:48 +020010651 if (unlikely(se_fl_test(ctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
10652 goto out;
10653
10654 /* The applet execution is already done. */
10655 if (http_ctx->flags & APPLET_DONE)
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010656 goto out;
10657
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010658 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010659 if (!b_size(&res->buf)) {
Christopher Faulet7b3d38a2023-05-05 11:28:45 +020010660 sc_need_room(sc, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010661 goto out;
10662 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010663
10664 /* Set the currently running flag. */
10665 if (!HLUA_IS_RUNNING(hlua) &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010666 !(http_ctx->flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +020010667 if (!co_data(req)) {
Willy Tarreau90e8b452022-05-25 18:21:43 +020010668 applet_need_more_data(ctx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010669 goto out;
10670 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010671 }
10672
Christopher Faulet31572222023-03-31 11:13:48 +020010673 /* Execute the function. */
10674 switch (hlua_ctx_resume(hlua, 1)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010675 /* finished. */
10676 case HLUA_E_OK:
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010677 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010678 break;
10679
10680 /* yield. */
10681 case HLUA_E_AGAIN:
10682 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010683 task_schedule(http_ctx->task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +010010684 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010685
10686 /* finished with error. */
10687 case HLUA_E_ERRMSG:
10688 /* Display log. */
10689 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010690 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010691 lua_pop(hlua->T, 1);
10692 goto error;
10693
10694 case HLUA_E_ETMOUT:
10695 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010696 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010697 goto error;
10698
10699 case HLUA_E_NOMEM:
10700 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010701 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010702 goto error;
10703
10704 case HLUA_E_YIELD: /* unexpected */
10705 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010706 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010707 goto error;
10708
10709 case HLUA_E_ERR:
10710 /* Display log. */
10711 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010712 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010713 goto error;
10714
10715 default:
10716 goto error;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010717 }
10718
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010719 if (http_ctx->flags & APPLET_DONE) {
10720 if (http_ctx->flags & APPLET_RSP_SENT)
Christopher Faulet31572222023-03-31 11:13:48 +020010721 goto out;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +010010722
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010723 if (!(http_ctx->flags & APPLET_HDR_SENT))
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010724 goto error;
10725
Christopher Fauletf89af9c2022-04-07 10:07:18 +020010726 /* no more data are expected. If the response buffer is empty
10727 * for a chunked message, be sure to add something (EOT block in
10728 * this case) to have something to send. It is important to be
10729 * sure the EOM flags will be handled by the endpoint.
10730 */
10731 if (htx_is_empty(res_htx) && (strm->txn->rsp.flags & (HTTP_MSGF_XFER_LEN|HTTP_MSGF_CNT_LEN)) == HTTP_MSGF_XFER_LEN) {
10732 if (!htx_add_endof(res_htx, HTX_BLK_EOT)) {
Christopher Faulet7b3d38a2023-05-05 11:28:45 +020010733 sc_need_room(sc, sizeof(struct htx_blk)+1);
Christopher Fauletf89af9c2022-04-07 10:07:18 +020010734 goto out;
10735 }
10736 channel_add_input(res, 1);
10737 }
10738
Christopher Fauletd1ac2b92020-12-02 19:12:22 +010010739 res_htx->flags |= HTX_FL_EOM;
Christopher Faulet31572222023-03-31 11:13:48 +020010740 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010741 strm->txn->status = http_ctx->status;
10742 http_ctx->flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010743 }
10744
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010745 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010746 htx_to_buf(res_htx, &res->buf);
Christopher Faulet31572222023-03-31 11:13:48 +020010747 /* eat the whole request */
10748 if (co_data(req)) {
10749 req_htx = htx_from_buf(&req->buf);
10750 co_htx_skip(req, req_htx, co_data(req));
10751 htx_to_buf(req_htx, &req->buf);
10752 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010753 return;
10754
10755 error:
10756
10757 /* If we are in HTTP mode, and we are not send any
10758 * data, return a 500 server error in best effort:
10759 * if there is no room available in the buffer,
10760 * just close the connection.
10761 */
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010762 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +020010763 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010764
10765 channel_erase(res);
10766 res->buf.data = b_data(err);
10767 memcpy(res->buf.area, b_head(err), b_data(err));
10768 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +010010769 channel_add_input(res, res_htx->data);
Christopher Faulet31572222023-03-31 11:13:48 +020010770 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010771 }
Christopher Faulet31572222023-03-31 11:13:48 +020010772 else
10773 se_fl_set(ctx->sedesc, SE_FL_ERROR);
10774
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010775 if (!(strm->flags & SF_ERR_MASK))
10776 strm->flags |= SF_ERR_RESOURCE;
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010777 http_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +020010778 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010779}
10780
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010781static void hlua_applet_http_release(struct appctx *ctx)
10782{
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010783 struct hlua_http_ctx *http_ctx = ctx->svcctx;
10784
10785 task_destroy(http_ctx->task);
10786 http_ctx->task = NULL;
10787 hlua_ctx_destroy(http_ctx->hlua);
10788 http_ctx->hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010789}
10790
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010791/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010792 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010793 *
10794 * This function can fail with an abort() due to an Lua critical error.
10795 * We are in the configuration parsing process of HAProxy, this abort() is
10796 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010797 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010798static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
10799 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010800{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010801 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010802 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010803
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010804 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010805 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010806 if (!rule->arg.hlua_rule) {
10807 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +020010808 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010809 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010810
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010811 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +020010812 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
10813 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010814 if (!rule->arg.hlua_rule->args) {
10815 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +020010816 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010817 }
10818
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010819 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010820 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010821
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010822 /* Expect some arguments */
10823 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +010010824 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010825 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +020010826 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010827 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +010010828 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010829 if (!rule->arg.hlua_rule->args[i]) {
10830 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +020010831 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010832 }
10833 (*cur_arg)++;
10834 }
10835 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010836
Thierry FOURNIER42148732015-09-02 17:17:33 +020010837 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010838 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +020010839 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +020010840
10841 error:
10842 if (rule->arg.hlua_rule) {
10843 if (rule->arg.hlua_rule->args) {
10844 for (i = 0; i < fcn->nargs; i++)
10845 ha_free(&rule->arg.hlua_rule->args[i]);
10846 ha_free(&rule->arg.hlua_rule->args);
10847 }
10848 ha_free(&rule->arg.hlua_rule);
10849 }
10850 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010851}
10852
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010853static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
10854 struct act_rule *rule, char **err)
10855{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010856 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010857
Thierry FOURNIER718e2a72015-12-20 20:13:14 +010010858 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010859 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +010010860 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010861 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +010010862 * the call of this analyzer.
10863 */
10864 if (rule->from != ACT_F_HTTP_REQ) {
10865 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
10866 return ACT_RET_PRS_ERR;
10867 }
10868
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010869 /* Memory for the rule. */
10870 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
10871 if (!rule->arg.hlua_rule) {
10872 memprintf(err, "out of memory error");
10873 return ACT_RET_PRS_ERR;
10874 }
10875
10876 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010877 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010878
10879 /* TODO: later accept arguments. */
10880 rule->arg.hlua_rule->args = NULL;
10881
10882 /* Add applet pointer in the rule. */
10883 rule->applet.obj_type = OBJ_TYPE_APPLET;
10884 rule->applet.name = fcn->name;
10885 rule->applet.init = hlua_applet_http_init;
10886 rule->applet.fct = hlua_applet_http_fct;
10887 rule->applet.release = hlua_applet_http_release;
10888 rule->applet.timeout = hlua_timeout_applet;
10889
10890 return ACT_RET_PRS_OK;
10891}
10892
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010893/* This function is an LUA binding used for registering
10894 * "sample-conv" functions. It expects a converter name used
10895 * in the haproxy configuration file, and an LUA function.
10896 */
10897__LJMP static int hlua_register_action(lua_State *L)
10898{
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010899 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010900 const char *name;
10901 int ref;
10902 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010903 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010904 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010905 struct buffer *trash;
10906 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010907
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010908 /* Initialise the number of expected arguments at 0. */
10909 nargs = 0;
10910
10911 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
10912 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010913
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010010914 if (hlua_gethlua(L)) {
10915 /* runtime processing */
10916 WILL_LJMP(luaL_error(L, "register_action: not available outside of body context"));
10917 }
10918
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010919 /* First argument : converter name. */
10920 name = MAY_LJMP(luaL_checkstring(L, 1));
10921
10922 /* Second argument : environment. */
10923 if (lua_type(L, 2) != LUA_TTABLE)
10924 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
10925
10926 /* Third argument : lua function. */
10927 ref = MAY_LJMP(hlua_checkfunction(L, 3));
10928
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010929 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010930 if (lua_gettop(L) >= 4)
10931 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
10932
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010933 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010934 lua_pushnil(L);
10935 while (lua_next(L, 2) != 0) {
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010936 if (lua_type(L, -1) != LUA_TSTRING) {
10937 hlua_unref(L, ref);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010938 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010939 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010940
Thierry Fournierf67442e2020-11-28 20:41:07 +010010941 /* Check if action exists */
10942 trash = get_trash_chunk();
10943 chunk_printf(trash, "lua.%s", name);
10944 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
10945 akw = tcp_req_cont_action(trash->area);
10946 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
10947 akw = tcp_res_cont_action(trash->area);
10948 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
10949 akw = action_http_req_custom(trash->area);
10950 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
10951 akw = action_http_res_custom(trash->area);
10952 } else {
10953 akw = NULL;
10954 }
10955 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010956 fcn = akw->private;
10957 if (fcn->function_ref[hlua_state_id] != -1) {
10958 ha_warning("Trying to register action 'lua.%s' more than once. "
10959 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010960 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010961 }
10962 fcn->function_ref[hlua_state_id] = ref;
10963
10964 /* pop the environment string. */
10965 lua_pop(L, 1);
10966 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010967 }
10968
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010969 /* Check required environment. Only accepted "http" or "tcp". */
10970 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010971 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010972 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010973 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010974 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010975 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010976 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010977
10978 /* Fill fcn. */
10979 fcn->name = strdup(name);
10980 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010981 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010982 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010983
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -070010984 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010985 fcn->nargs = nargs;
10986
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010987 /* List head */
10988 akl->list.n = akl->list.p = NULL;
10989
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010990 /* action keyword. */
10991 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010992 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010993 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010994 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010995
10996 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
10997
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020010998 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010999 akl->kw[0].private = fcn;
11000 akl->kw[0].parse = action_register_lua;
11001
11002 /* select the action registering point. */
11003 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
11004 tcp_req_cont_keywords_register(akl);
11005 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
11006 tcp_res_cont_keywords_register(akl);
11007 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
11008 http_req_keywords_register(akl);
11009 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
11010 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011011 else {
11012 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011013 hlua_unref(L, ref);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011014 if (akl)
11015 ha_free((char **)&(akl->kw[0].kw));
11016 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010011017 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011018 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
11019 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011020 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011021
11022 /* pop the environment string. */
11023 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011024
11025 /* reset for next loop */
11026 akl = NULL;
11027 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011028 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011029 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011030
11031 alloc_error:
11032 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011033 hlua_unref(L, ref);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011034 ha_free(&akl);
11035 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11036 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011037}
11038
11039static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
11040 struct act_rule *rule, char **err)
11041{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020011042 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011043
Christopher Faulet280f85b2019-07-15 15:02:04 +020011044 if (px->mode == PR_MODE_HTTP) {
11045 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +010011046 return ACT_RET_PRS_ERR;
11047 }
11048
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011049 /* Memory for the rule. */
11050 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
11051 if (!rule->arg.hlua_rule) {
11052 memprintf(err, "out of memory error");
11053 return ACT_RET_PRS_ERR;
11054 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011055
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011056 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010011057 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011058
11059 /* TODO: later accept arguments. */
11060 rule->arg.hlua_rule->args = NULL;
11061
11062 /* Add applet pointer in the rule. */
11063 rule->applet.obj_type = OBJ_TYPE_APPLET;
11064 rule->applet.name = fcn->name;
11065 rule->applet.init = hlua_applet_tcp_init;
11066 rule->applet.fct = hlua_applet_tcp_fct;
11067 rule->applet.release = hlua_applet_tcp_release;
11068 rule->applet.timeout = hlua_timeout_applet;
11069
11070 return 0;
11071}
11072
11073/* This function is an LUA binding used for registering
11074 * "sample-conv" functions. It expects a converter name used
11075 * in the haproxy configuration file, and an LUA function.
11076 */
11077__LJMP static int hlua_register_service(lua_State *L)
11078{
11079 struct action_kw_list *akl;
11080 const char *name;
11081 const char *env;
11082 int ref;
11083 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +020011084 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011085 struct buffer *trash;
11086 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011087
11088 MAY_LJMP(check_args(L, 3, "register_service"));
11089
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010011090 if (hlua_gethlua(L)) {
11091 /* runtime processing */
11092 WILL_LJMP(luaL_error(L, "register_service: not available outside of body context"));
11093 }
11094
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011095 /* First argument : converter name. */
11096 name = MAY_LJMP(luaL_checkstring(L, 1));
11097
11098 /* Second argument : environment. */
11099 env = MAY_LJMP(luaL_checkstring(L, 2));
11100
11101 /* Third argument : lua function. */
11102 ref = MAY_LJMP(hlua_checkfunction(L, 3));
11103
Thierry Fournierf67442e2020-11-28 20:41:07 +010011104 /* Check for service already registered */
11105 trash = get_trash_chunk();
11106 chunk_printf(trash, "lua.%s", name);
11107 akw = service_find(trash->area);
11108 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010011109 fcn = akw->private;
11110 if (fcn->function_ref[hlua_state_id] != -1) {
11111 ha_warning("Trying to register service 'lua.%s' more than once. "
11112 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011113 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011114 }
11115 fcn->function_ref[hlua_state_id] = ref;
11116 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011117 }
11118
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011119 /* Allocate and fill the sample fetch keyword struct. */
11120 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
11121 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011122 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010011123 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011124 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011125 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011126
11127 /* Fill fcn. */
11128 len = strlen("<lua.>") + strlen(name) + 1;
11129 fcn->name = calloc(1, len);
11130 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011131 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011132 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +010011133 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011134
11135 /* List head */
11136 akl->list.n = akl->list.p = NULL;
11137
11138 /* converter keyword. */
11139 len = strlen("lua.") + strlen(name) + 1;
11140 akl->kw[0].kw = calloc(1, len);
11141 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011142 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011143
11144 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
11145
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +010011146 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011147 if (strcmp(env, "tcp") == 0)
11148 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020011149 else if (strcmp(env, "http") == 0)
11150 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +020011151 else {
11152 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011153 hlua_unref(L, ref);
Christopher Faulet5c028d72021-04-12 15:11:44 +020011154 if (akl)
11155 ha_free((char **)&(akl->kw[0].kw));
11156 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010011157 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +010011158 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +020011159 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011160
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020011161 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011162 akl->kw[0].private = fcn;
11163
11164 /* End of array. */
11165 memset(&akl->kw[1], 0, sizeof(*akl->kw));
11166
11167 /* Register this new converter */
11168 service_keywords_register(akl);
11169
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011170 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +020011171
11172 alloc_error:
11173 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011174 hlua_unref(L, ref);
Christopher Faulet5c028d72021-04-12 15:11:44 +020011175 ha_free(&akl);
11176 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11177 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011178}
11179
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011180/* This function initialises Lua cli handler. It copies the
11181 * arguments in the Lua stack and create channel IO objects.
11182 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +020011183static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011184{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011185 struct hlua_cli_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011186 struct hlua *hlua;
11187 struct hlua_function *fcn;
11188 int i;
11189 const char *error;
11190
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011191 fcn = private;
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011192 ctx->fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010011193
Willy Tarreaubafbe012017-11-24 17:34:44 +010011194 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010011195 if (!hlua) {
11196 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010011197 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010011198 }
11199 HLUA_INIT(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011200 ctx->hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011201
11202 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +050011203 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011204 * applet_http. It is absolutely compatible.
11205 */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011206 ctx->task = task_new_here();
11207 if (!ctx->task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +010011208 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010011209 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011210 }
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011211 ctx->task->nice = 0;
11212 ctx->task->context = appctx;
11213 ctx->task->process = hlua_applet_wakeup;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011214
11215 /* Initialises the Lua context */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010011216 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), ctx->task)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011217 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010011218 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011219 }
11220
11221 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010011222 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011223 if (lua_type(hlua->T, -1) == LUA_TSTRING)
11224 error = lua_tostring(hlua->T, -1);
11225 else
11226 error = "critical error";
11227 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
11228 goto error;
11229 }
11230
11231 /* Check stack available size. */
11232 if (!lua_checkstack(hlua->T, 2)) {
11233 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
11234 goto error;
11235 }
11236
11237 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011238 hlua_pushref(hlua->T, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011239
11240 /* Once the arguments parsed, the CLI is like an AppletTCP,
11241 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011242 */
11243 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
11244 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
11245 goto error;
11246 }
11247 hlua->nargs = 1;
11248
11249 /* push keywords in the stack. */
11250 for (i = 0; *args[i]; i++) {
11251 /* Check stack available size. */
11252 if (!lua_checkstack(hlua->T, 1)) {
11253 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
11254 goto error;
11255 }
11256 lua_pushstring(hlua->T, args[i]);
11257 hlua->nargs++;
11258 }
11259
11260 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010011261 hlua_timer_init(&hlua->timer, hlua_timeout_session);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011262
11263 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010011264 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011265
11266 /* It's ok */
11267 return 0;
11268
11269 /* It's not ok. */
11270error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +010011271 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011272 hlua_ctx_destroy(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011273 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011274 return 1;
11275}
11276
11277static int hlua_cli_io_handler_fct(struct appctx *appctx)
11278{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011279 struct hlua_cli_ctx *ctx = appctx->svcctx;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011280 struct hlua *hlua;
Willy Tarreau475e4632022-05-27 10:26:46 +020011281 struct stconn *sc;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011282 struct hlua_function *fcn;
11283
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011284 hlua = ctx->hlua;
Willy Tarreauc12b3212022-05-27 11:08:15 +020011285 sc = appctx_sc(appctx);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011286 fcn = ctx->fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011287
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011288 /* Execute the function. */
11289 switch (hlua_ctx_resume(hlua, 1)) {
11290
11291 /* finished. */
11292 case HLUA_E_OK:
11293 return 1;
11294
11295 /* yield. */
11296 case HLUA_E_AGAIN:
11297 /* We want write. */
11298 if (HLUA_IS_WAKERESWR(hlua))
Christopher Faulet7b3d38a2023-05-05 11:28:45 +020011299 sc_need_room(sc, -1);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011300 /* Set the timeout. */
11301 if (hlua->wake_time != TICK_ETERNITY)
11302 task_schedule(hlua->task, hlua->wake_time);
11303 return 0;
11304
11305 /* finished with error. */
11306 case HLUA_E_ERRMSG:
11307 /* Display log. */
11308 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
11309 fcn->name, lua_tostring(hlua->T, -1));
11310 lua_pop(hlua->T, 1);
11311 return 1;
11312
Thierry Fournierd5b073c2018-05-21 19:42:47 +020011313 case HLUA_E_ETMOUT:
11314 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
11315 fcn->name);
11316 return 1;
11317
11318 case HLUA_E_NOMEM:
11319 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
11320 fcn->name);
11321 return 1;
11322
11323 case HLUA_E_YIELD: /* unexpected */
11324 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
11325 fcn->name);
11326 return 1;
11327
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011328 case HLUA_E_ERR:
11329 /* Display log. */
11330 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
11331 fcn->name);
11332 return 1;
11333
11334 default:
11335 return 1;
11336 }
11337
11338 return 1;
11339}
11340
11341static void hlua_cli_io_release_fct(struct appctx *appctx)
11342{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011343 struct hlua_cli_ctx *ctx = appctx->svcctx;
11344
11345 hlua_ctx_destroy(ctx->hlua);
11346 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011347}
11348
11349/* This function is an LUA binding used for registering
11350 * new keywords in the cli. It expects a list of keywords
11351 * which are the "path". It is limited to 5 keywords. A
11352 * description of the command, a function to be executed
11353 * for the parsing and a function for io handlers.
11354 */
11355__LJMP static int hlua_register_cli(lua_State *L)
11356{
11357 struct cli_kw_list *cli_kws;
11358 const char *message;
11359 int ref_io;
11360 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011361 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011362 int index;
11363 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011364 struct buffer *trash;
11365 const char *kw[5];
11366 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011367 const char *errmsg;
Willy Tarreau22450af2023-04-07 15:27:55 +020011368 char *end;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011369
11370 MAY_LJMP(check_args(L, 3, "register_cli"));
11371
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010011372 if (hlua_gethlua(L)) {
11373 /* runtime processing */
11374 WILL_LJMP(luaL_error(L, "register_cli: not available outside of body context"));
11375 }
11376
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011377 /* First argument : an array of maximum 5 keywords. */
11378 if (!lua_istable(L, 1))
11379 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
11380
11381 /* Second argument : string with contextual message. */
11382 message = MAY_LJMP(luaL_checkstring(L, 2));
11383
11384 /* Third and fourth argument : lua function. */
11385 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
11386
Thierry Fournierf67442e2020-11-28 20:41:07 +010011387 /* Check for CLI service already registered */
11388 trash = get_trash_chunk();
11389 index = 0;
11390 lua_pushnil(L);
11391 memset(kw, 0, sizeof(kw));
11392 while (lua_next(L, 1) != 0) {
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011393 if (index >= CLI_PREFIX_KW_NB) {
11394 hlua_unref(L, ref_io);
Thierry Fournierf67442e2020-11-28 20:41:07 +010011395 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011396 }
11397 if (lua_type(L, -1) != LUA_TSTRING) {
11398 hlua_unref(L, ref_io);
Thierry Fournierf67442e2020-11-28 20:41:07 +010011399 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011400 }
Thierry Fournierf67442e2020-11-28 20:41:07 +010011401 kw[index] = lua_tostring(L, -1);
11402 if (index == 0)
11403 chunk_printf(trash, "%s", kw[index]);
11404 else
11405 chunk_appendf(trash, " %s", kw[index]);
11406 index++;
11407 lua_pop(L, 1);
11408 }
11409 cli_kw = cli_find_kw_exact((char **)kw);
11410 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010011411 fcn = cli_kw->private;
11412 if (fcn->function_ref[hlua_state_id] != -1) {
11413 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
11414 "This will become a hard error in version 2.5.\n", trash->area);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011415 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011416 }
11417 fcn->function_ref[hlua_state_id] = ref_io;
11418 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011419 }
11420
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011421 /* Allocate and fill the sample fetch keyword struct. */
11422 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011423 if (!cli_kws) {
11424 errmsg = "Lua out of memory error.";
11425 goto error;
11426 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +010011427 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011428 if (!fcn) {
11429 errmsg = "Lua out of memory error.";
11430 goto error;
11431 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011432
11433 /* Fill path. */
11434 index = 0;
11435 lua_pushnil(L);
11436 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011437 if (index >= 5) {
11438 errmsg = "1st argument must be a table with a maximum of 5 entries";
11439 goto error;
11440 }
11441 if (lua_type(L, -1) != LUA_TSTRING) {
11442 errmsg = "1st argument must be a table filled with strings";
11443 goto error;
11444 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011445 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011446 if (!cli_kws->kw[0].str_kw[index]) {
11447 errmsg = "Lua out of memory error.";
11448 goto error;
11449 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011450 index++;
11451 lua_pop(L, 1);
11452 }
11453
11454 /* Copy help message. */
11455 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011456 if (!cli_kws->kw[0].usage) {
11457 errmsg = "Lua out of memory error.";
11458 goto error;
11459 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011460
11461 /* Fill fcn io handler. */
11462 len = strlen("<lua.cli>") + 1;
11463 for (i = 0; i < index; i++)
11464 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
11465 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011466 if (!fcn->name) {
11467 errmsg = "Lua out of memory error.";
11468 goto error;
11469 }
Willy Tarreau22450af2023-04-07 15:27:55 +020011470
11471 end = fcn->name;
11472 len = 8;
11473 memcpy(end, "<lua.cli", len);
11474 end += len;
11475
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011476 for (i = 0; i < index; i++) {
Willy Tarreau22450af2023-04-07 15:27:55 +020011477 *(end++) = '.';
11478 len = strlen(cli_kws->kw[0].str_kw[i]);
11479 memcpy(end, cli_kws->kw[0].str_kw[i], len);
11480 end += len;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011481 }
Willy Tarreau22450af2023-04-07 15:27:55 +020011482 *(end++) = '>';
11483 *(end++) = 0;
11484
Thierry Fournierc7492592020-11-28 23:57:24 +010011485 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011486
11487 /* Fill last entries. */
11488 cli_kws->kw[0].private = fcn;
11489 cli_kws->kw[0].parse = hlua_cli_parse_fct;
11490 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
11491 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
11492
11493 /* Register this new converter */
11494 cli_register_kw(cli_kws);
11495
11496 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011497
11498 error:
11499 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011500 hlua_unref(L, ref_io);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011501 if (cli_kws) {
11502 for (i = 0; i < index; i++)
11503 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
11504 ha_free((char **)&(cli_kws->kw[0].usage));
11505 }
11506 ha_free(&cli_kws);
11507 WILL_LJMP(luaL_error(L, errmsg));
11508 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011509}
11510
Christopher Faulet69c581a2021-05-31 08:54:04 +020011511static int hlua_filter_init_per_thread(struct proxy *px, struct flt_conf *fconf)
11512{
11513 struct hlua_flt_config *conf = fconf->conf;
11514 lua_State *L;
11515 int error, pos, state_id, flt_ref;
11516
11517 state_id = reg_flt_to_stack_id(conf->reg);
11518 L = hlua_states[state_id];
11519 pos = lua_gettop(L);
11520
11521 /* The filter parsing function */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011522 hlua_pushref(L, conf->reg->fun_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011523
11524 /* Push the filter class on the stack and resolve all callbacks */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011525 hlua_pushref(L, conf->reg->flt_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011526
11527 /* Duplicate the filter class so each filter will have its own copy */
11528 lua_newtable(L);
11529 lua_pushnil(L);
11530
11531 while (lua_next(L, pos+2)) {
11532 lua_pushvalue(L, -2);
11533 lua_insert(L, -2);
11534 lua_settable(L, -4);
11535 }
Aurelien DARRAGON73d1a982023-03-20 17:42:08 +010011536 flt_ref = hlua_ref(L);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011537
11538 /* Remove the original lua filter class from the stack */
11539 lua_pop(L, 1);
11540
11541 /* Push the copy on the stack */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011542 hlua_pushref(L, flt_ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011543
11544 /* extra args are pushed in a table */
11545 lua_newtable(L);
11546 for (pos = 0; conf->args[pos]; pos++) {
11547 /* Check stack available size. */
11548 if (!lua_checkstack(L, 1)) {
11549 ha_alert("Lua filter '%s' : Lua error : full stack.", conf->reg->name);
11550 goto error;
11551 }
11552 lua_pushstring(L, conf->args[pos]);
11553 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
11554 }
11555
11556 error = lua_pcall(L, 2, LUA_MULTRET, 0);
11557 switch (error) {
11558 case LUA_OK:
11559 /* replace the filter ref */
11560 conf->ref[state_id] = flt_ref;
11561 break;
11562 case LUA_ERRRUN:
11563 ha_alert("Lua filter '%s' : runtime error : %s", conf->reg->name, lua_tostring(L, -1));
11564 goto error;
11565 case LUA_ERRMEM:
11566 ha_alert("Lua filter '%s' : out of memory error", conf->reg->name);
11567 goto error;
11568 case LUA_ERRERR:
11569 ha_alert("Lua filter '%s' : message handler error : %s", conf->reg->name, lua_tostring(L, -1));
11570 goto error;
11571#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
11572 case LUA_ERRGCMM:
11573 ha_alert("Lua filter '%s' : garbage collector error : %s", conf->reg->name, lua_tostring(L, -1));
11574 goto error;
11575#endif
11576 default:
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050011577 ha_alert("Lua filter '%s' : unknown error : %s", conf->reg->name, lua_tostring(L, -1));
Christopher Faulet69c581a2021-05-31 08:54:04 +020011578 goto error;
11579 }
11580
11581 lua_settop(L, 0);
11582 return 0;
11583
11584 error:
11585 lua_settop(L, 0);
11586 return -1;
11587}
11588
11589static void hlua_filter_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
11590{
11591 struct hlua_flt_config *conf = fconf->conf;
11592 lua_State *L;
11593 int state_id;
11594
11595 if (!conf)
11596 return;
11597
11598 state_id = reg_flt_to_stack_id(conf->reg);
11599 L = hlua_states[state_id];
Aurelien DARRAGONfde199d2023-03-20 15:09:33 +010011600 hlua_unref(L, conf->ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011601}
11602
11603static int hlua_filter_init(struct proxy *px, struct flt_conf *fconf)
11604{
11605 struct hlua_flt_config *conf = fconf->conf;
11606 int state_id = reg_flt_to_stack_id(conf->reg);
11607
11608 /* Rely on per-thread init for global scripts */
11609 if (!state_id)
11610 return hlua_filter_init_per_thread(px, fconf);
11611 return 0;
11612}
11613
11614static void hlua_filter_deinit(struct proxy *px, struct flt_conf *fconf)
11615{
11616
11617 if (fconf->conf) {
11618 struct hlua_flt_config *conf = fconf->conf;
11619 int state_id = reg_flt_to_stack_id(conf->reg);
11620 int pos;
11621
11622 /* Rely on per-thread deinit for global scripts */
11623 if (!state_id)
11624 hlua_filter_deinit_per_thread(px, fconf);
11625
11626 for (pos = 0; conf->args[pos]; pos++)
11627 free(conf->args[pos]);
11628 free(conf->args);
11629 }
11630 ha_free(&fconf->conf);
11631 ha_free((char **)&fconf->id);
11632 ha_free(&fconf->ops);
11633}
11634
11635static int hlua_filter_new(struct stream *s, struct filter *filter)
11636{
11637 struct hlua_flt_config *conf = FLT_CONF(filter);
11638 struct hlua_flt_ctx *flt_ctx = NULL;
11639 int ret = 1;
11640
Aurelien DARRAGONb25d5d32023-08-09 14:56:19 +020011641 if (!hlua_stream_ctx_prepare(s, reg_flt_to_stack_id(conf->reg))) {
11642 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11643 conf->reg->name);
11644 ret = 0;
11645 goto end;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011646 }
11647
11648 flt_ctx = pool_zalloc(pool_head_hlua_flt_ctx);
11649 if (!flt_ctx) {
11650 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11651 conf->reg->name);
11652 ret = 0;
11653 goto end;
11654 }
11655 flt_ctx->hlua[0] = pool_alloc(pool_head_hlua);
11656 flt_ctx->hlua[1] = pool_alloc(pool_head_hlua);
11657 if (!flt_ctx->hlua[0] || !flt_ctx->hlua[1]) {
11658 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11659 conf->reg->name);
11660 ret = 0;
11661 goto end;
11662 }
11663 HLUA_INIT(flt_ctx->hlua[0]);
11664 HLUA_INIT(flt_ctx->hlua[1]);
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010011665 if (!hlua_ctx_init(flt_ctx->hlua[0], reg_flt_to_stack_id(conf->reg), s->task) ||
11666 !hlua_ctx_init(flt_ctx->hlua[1], reg_flt_to_stack_id(conf->reg), s->task)) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020011667 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11668 conf->reg->name);
11669 ret = 0;
11670 goto end;
11671 }
11672
11673 if (!HLUA_IS_RUNNING(s->hlua)) {
11674 /* The following Lua calls can fail. */
11675 if (!SET_SAFE_LJMP(s->hlua)) {
11676 const char *error;
11677
11678 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
11679 error = lua_tostring(s->hlua->T, -1);
11680 else
11681 error = "critical error";
11682 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
11683 ret = 0;
11684 goto end;
11685 }
11686
11687 /* Check stack size. */
11688 if (!lua_checkstack(s->hlua->T, 1)) {
11689 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
Tim Duesterhus22817382021-09-11 23:17:25 +020011690 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011691 ret = 0;
11692 goto end;
11693 }
11694
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011695 hlua_pushref(s->hlua->T, conf->ref[s->hlua->state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011696 if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) {
11697 SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
11698 conf->reg->name);
11699 RESET_SAFE_LJMP(s->hlua);
11700 ret = 0;
11701 goto end;
11702 }
11703 lua_insert(s->hlua->T, -2);
11704
11705 /* Push the copy on the stack */
11706 s->hlua->nargs = 1;
11707
11708 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010011709 hlua_timer_init(&s->hlua->timer, hlua_timeout_session);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011710
11711 /* At this point the execution is safe. */
11712 RESET_SAFE_LJMP(s->hlua);
11713 }
11714
11715 switch (hlua_ctx_resume(s->hlua, 0)) {
11716 case HLUA_E_OK:
11717 /* Nothing returned or not a table, ignore the filter for current stream */
11718 if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) {
11719 ret = 0;
11720 goto end;
11721 }
11722
11723 /* Attached the filter pointer to the ctx */
11724 lua_pushstring(s->hlua->T, "__filter");
11725 lua_pushlightuserdata(s->hlua->T, filter);
11726 lua_settable(s->hlua->T, -3);
11727
11728 /* Save a ref on the filter ctx */
11729 lua_pushvalue(s->hlua->T, 1);
Aurelien DARRAGON73d1a982023-03-20 17:42:08 +010011730 flt_ctx->ref = hlua_ref(s->hlua->T);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011731 filter->ctx = flt_ctx;
11732 break;
11733 case HLUA_E_ERRMSG:
11734 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(s->hlua->T, -1));
11735 ret = -1;
11736 goto end;
11737 case HLUA_E_ETMOUT:
11738 SEND_ERR(s->be, "Lua filter '%s' : 'new' execution timeout.\n", conf->reg->name);
11739 ret = 0;
11740 goto end;
11741 case HLUA_E_NOMEM:
11742 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
11743 ret = 0;
11744 goto end;
11745 case HLUA_E_AGAIN:
11746 case HLUA_E_YIELD:
11747 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
11748 " are not allowed from 'new' function.\n", conf->reg->name);
11749 ret = 0;
11750 goto end;
11751 case HLUA_E_ERR:
11752 SEND_ERR(s->be, "Lua filter '%s': 'new' returns an unknown error.\n", conf->reg->name);
11753 ret = 0;
11754 goto end;
11755 default:
11756 ret = 0;
11757 goto end;
11758 }
11759
11760 end:
11761 if (s->hlua)
11762 lua_settop(s->hlua->T, 0);
11763 if (ret <= 0) {
11764 if (flt_ctx) {
11765 hlua_ctx_destroy(flt_ctx->hlua[0]);
11766 hlua_ctx_destroy(flt_ctx->hlua[1]);
11767 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
11768 }
11769 }
11770 return ret;
11771}
11772
11773static void hlua_filter_delete(struct stream *s, struct filter *filter)
11774{
11775 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11776
Aurelien DARRAGONfde199d2023-03-20 15:09:33 +010011777 hlua_unref(s->hlua->T, flt_ctx->ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011778 hlua_ctx_destroy(flt_ctx->hlua[0]);
11779 hlua_ctx_destroy(flt_ctx->hlua[1]);
11780 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
11781 filter->ctx = NULL;
11782}
11783
Christopher Faulet9f55a502020-02-25 15:21:02 +010011784static int hlua_filter_from_payload(struct filter *filter)
11785{
11786 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11787
11788 return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD));
11789}
11790
Christopher Fauletc404f112020-02-26 15:03:09 +010011791static int hlua_filter_callback(struct stream *s, struct filter *filter, const char *fun,
11792 int dir, unsigned int flags)
11793{
11794 struct hlua *flt_hlua;
11795 struct hlua_flt_config *conf = FLT_CONF(filter);
11796 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11797 unsigned int hflags = HLUA_TXN_FLT_CTX;
11798 int ret = 1;
11799
11800 flt_hlua = flt_ctx->hlua[(dir == SMP_OPT_DIR_REQ ? 0 : 1)];
11801 if (!flt_hlua)
11802 goto end;
11803
11804 if (!HLUA_IS_RUNNING(flt_hlua)) {
11805 int extra_idx = lua_gettop(flt_hlua->T);
11806
11807 /* The following Lua calls can fail. */
11808 if (!SET_SAFE_LJMP(flt_hlua)) {
11809 const char *error;
11810
11811 if (lua_type(flt_hlua->T, -1) == LUA_TSTRING)
11812 error = lua_tostring(flt_hlua->T, -1);
11813 else
11814 error = "critical error";
11815 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
11816 goto end;
11817 }
11818
11819 /* Check stack size. */
11820 if (!lua_checkstack(flt_hlua->T, 3)) {
11821 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
11822 RESET_SAFE_LJMP(flt_hlua);
11823 goto end;
11824 }
11825
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011826 hlua_pushref(flt_hlua->T, flt_ctx->ref);
Christopher Fauletc404f112020-02-26 15:03:09 +010011827 if (lua_getfield(flt_hlua->T, -1, fun) != LUA_TFUNCTION) {
11828 RESET_SAFE_LJMP(flt_hlua);
11829 goto end;
11830 }
11831 lua_insert(flt_hlua->T, -2);
11832
11833 if (!hlua_txn_new(flt_hlua->T, s, s->be, dir, hflags)) {
11834 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
11835 RESET_SAFE_LJMP(flt_hlua);
11836 goto end;
11837 }
11838 flt_hlua->nargs = 2;
11839
11840 if (flags & HLUA_FLT_CB_ARG_CHN) {
11841 if (dir == SMP_OPT_DIR_REQ)
11842 lua_getfield(flt_hlua->T, -1, "req");
11843 else
11844 lua_getfield(flt_hlua->T, -1, "res");
11845 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
11846 lua_pushstring(flt_hlua->T, "__filter");
11847 lua_pushlightuserdata(flt_hlua->T, filter);
11848 lua_settable(flt_hlua->T, -3);
11849 }
11850 flt_hlua->nargs++;
11851 }
11852 else if (flags & HLUA_FLT_CB_ARG_HTTP_MSG) {
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011853 if (dir == SMP_OPT_DIR_REQ)
11854 lua_getfield(flt_hlua->T, -1, "http_req");
11855 else
11856 lua_getfield(flt_hlua->T, -1, "http_res");
11857 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
11858 lua_pushstring(flt_hlua->T, "__filter");
11859 lua_pushlightuserdata(flt_hlua->T, filter);
11860 lua_settable(flt_hlua->T, -3);
11861 }
11862 flt_hlua->nargs++;
Christopher Fauletc404f112020-02-26 15:03:09 +010011863 }
11864
11865 /* Check stack size. */
11866 if (!lua_checkstack(flt_hlua->T, 1)) {
11867 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
11868 RESET_SAFE_LJMP(flt_hlua);
11869 goto end;
11870 }
11871
11872 while (extra_idx--) {
11873 lua_pushvalue(flt_hlua->T, 1);
11874 lua_remove(flt_hlua->T, 1);
11875 flt_hlua->nargs++;
11876 }
11877
11878 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010011879 hlua_timer_init(&flt_hlua->timer, hlua_timeout_session);
Christopher Fauletc404f112020-02-26 15:03:09 +010011880
11881 /* At this point the execution is safe. */
11882 RESET_SAFE_LJMP(flt_hlua);
11883 }
11884
11885 switch (hlua_ctx_resume(flt_hlua, !(flags & HLUA_FLT_CB_FINAL))) {
11886 case HLUA_E_OK:
11887 /* Catch the return value if it required */
11888 if ((flags & HLUA_FLT_CB_RETVAL) && lua_gettop(flt_hlua->T) > 0) {
11889 ret = lua_tointeger(flt_hlua->T, -1);
11890 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11891 }
11892
11893 /* Set timeout in the required channel. */
11894 if (flt_hlua->wake_time != TICK_ETERNITY) {
11895 if (dir == SMP_OPT_DIR_REQ)
11896 s->req.analyse_exp = flt_hlua->wake_time;
11897 else
11898 s->res.analyse_exp = flt_hlua->wake_time;
11899 }
11900 break;
11901 case HLUA_E_AGAIN:
11902 /* Set timeout in the required channel. */
11903 if (flt_hlua->wake_time != TICK_ETERNITY) {
11904 if (dir == SMP_OPT_DIR_REQ)
11905 s->req.analyse_exp = flt_hlua->wake_time;
11906 else
11907 s->res.analyse_exp = flt_hlua->wake_time;
11908 }
11909 /* Some actions can be wake up when a "write" event
11910 * is detected on a response channel. This is useful
11911 * only for actions targeted on the requests.
11912 */
11913 if (HLUA_IS_WAKERESWR(flt_hlua))
11914 s->res.flags |= CF_WAKE_WRITE;
11915 if (HLUA_IS_WAKEREQWR(flt_hlua))
11916 s->req.flags |= CF_WAKE_WRITE;
11917 ret = 0;
11918 goto end;
11919 case HLUA_E_ERRMSG:
11920 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(flt_hlua->T, -1));
11921 ret = -1;
11922 goto end;
11923 case HLUA_E_ETMOUT:
11924 SEND_ERR(s->be, "Lua filter '%s' : '%s' callback execution timeout.\n", conf->reg->name, fun);
11925 goto end;
11926 case HLUA_E_NOMEM:
11927 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
11928 goto end;
11929 case HLUA_E_YIELD:
11930 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
11931 " are not allowed from '%s' callback.\n", conf->reg->name, fun);
11932 goto end;
11933 case HLUA_E_ERR:
11934 SEND_ERR(s->be, "Lua filter '%s': '%s' returns an unknown error.\n", conf->reg->name, fun);
11935 goto end;
11936 default:
11937 goto end;
11938 }
11939
11940
11941 end:
11942 return ret;
11943}
11944
11945static int hlua_filter_start_analyze(struct stream *s, struct filter *filter, struct channel *chn)
11946{
11947 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11948
11949 flt_ctx->flags = 0;
11950 return hlua_filter_callback(s, filter, "start_analyze",
11951 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11952 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
11953}
11954
11955static int hlua_filter_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
11956{
11957 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11958
11959 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11960 return hlua_filter_callback(s, filter, "end_analyze",
11961 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11962 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
11963}
11964
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011965static int hlua_filter_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
11966{
11967 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11968
11969 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11970 return hlua_filter_callback(s, filter, "http_headers",
11971 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11972 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
11973}
11974
11975static int hlua_filter_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
11976 unsigned int offset, unsigned int len)
11977{
11978 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11979 struct hlua *flt_hlua;
11980 int dir = (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
11981 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
11982 int ret;
11983
11984 flt_hlua = flt_ctx->hlua[idx];
11985 flt_ctx->cur_off[idx] = offset;
11986 flt_ctx->cur_len[idx] = len;
11987 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
11988 ret = hlua_filter_callback(s, filter, "http_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_HTTP_MSG));
11989 if (ret != -1) {
11990 ret = flt_ctx->cur_len[idx];
11991 if (lua_gettop(flt_hlua->T) > 0) {
11992 ret = lua_tointeger(flt_hlua->T, -1);
11993 if (ret > flt_ctx->cur_len[idx])
11994 ret = flt_ctx->cur_len[idx];
11995 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11996 }
11997 }
11998 return ret;
11999}
12000
12001static int hlua_filter_http_end(struct stream *s, struct filter *filter, struct http_msg *msg)
12002{
12003 struct hlua_flt_ctx *flt_ctx = filter->ctx;
12004
12005 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
12006 return hlua_filter_callback(s, filter, "http_end",
12007 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
12008 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
12009}
12010
Christopher Fauletc404f112020-02-26 15:03:09 +010012011static int hlua_filter_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
12012 unsigned int offset, unsigned int len)
12013{
12014 struct hlua_flt_ctx *flt_ctx = filter->ctx;
12015 struct hlua *flt_hlua;
12016 int dir = (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
12017 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
12018 int ret;
12019
12020 flt_hlua = flt_ctx->hlua[idx];
12021 flt_ctx->cur_off[idx] = offset;
12022 flt_ctx->cur_len[idx] = len;
12023 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
12024 ret = hlua_filter_callback(s, filter, "tcp_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_CHN));
12025 if (ret != -1) {
12026 ret = flt_ctx->cur_len[idx];
12027 if (lua_gettop(flt_hlua->T) > 0) {
12028 ret = lua_tointeger(flt_hlua->T, -1);
12029 if (ret > flt_ctx->cur_len[idx])
12030 ret = flt_ctx->cur_len[idx];
12031 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
12032 }
12033 }
12034 return ret;
12035}
12036
Christopher Faulet69c581a2021-05-31 08:54:04 +020012037static int hlua_filter_parse_fct(char **args, int *cur_arg, struct proxy *px,
12038 struct flt_conf *fconf, char **err, void *private)
12039{
12040 struct hlua_reg_filter *reg_flt = private;
12041 lua_State *L;
12042 struct hlua_flt_config *conf = NULL;
12043 const char *flt_id = NULL;
12044 int state_id, pos, flt_flags = 0;
12045 struct flt_ops *hlua_flt_ops = NULL;
12046
12047 state_id = reg_flt_to_stack_id(reg_flt);
12048 L = hlua_states[state_id];
12049
12050 /* Initialize the filter ops with default callbacks */
12051 hlua_flt_ops = calloc(1, sizeof(*hlua_flt_ops));
Christopher Fauletc86bb872021-08-13 08:33:57 +020012052 if (!hlua_flt_ops)
12053 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012054 hlua_flt_ops->init = hlua_filter_init;
12055 hlua_flt_ops->deinit = hlua_filter_deinit;
12056 if (state_id) {
12057 /* Set per-thread callback if script is loaded per-thread */
12058 hlua_flt_ops->init_per_thread = hlua_filter_init_per_thread;
12059 hlua_flt_ops->deinit_per_thread = hlua_filter_deinit_per_thread;
12060 }
12061 hlua_flt_ops->attach = hlua_filter_new;
12062 hlua_flt_ops->detach = hlua_filter_delete;
12063
12064 /* Push the filter class on the stack and resolve all callbacks */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010012065 hlua_pushref(L, reg_flt->flt_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012066
Christopher Fauletc404f112020-02-26 15:03:09 +010012067 if (lua_getfield(L, -1, "start_analyze") == LUA_TFUNCTION)
12068 hlua_flt_ops->channel_start_analyze = hlua_filter_start_analyze;
12069 lua_pop(L, 1);
12070 if (lua_getfield(L, -1, "end_analyze") == LUA_TFUNCTION)
12071 hlua_flt_ops->channel_end_analyze = hlua_filter_end_analyze;
12072 lua_pop(L, 1);
Christopher Fauleteae8afa2020-02-26 17:15:48 +010012073 if (lua_getfield(L, -1, "http_headers") == LUA_TFUNCTION)
12074 hlua_flt_ops->http_headers = hlua_filter_http_headers;
12075 lua_pop(L, 1);
12076 if (lua_getfield(L, -1, "http_payload") == LUA_TFUNCTION)
12077 hlua_flt_ops->http_payload = hlua_filter_http_payload;
12078 lua_pop(L, 1);
12079 if (lua_getfield(L, -1, "http_end") == LUA_TFUNCTION)
12080 hlua_flt_ops->http_end = hlua_filter_http_end;
12081 lua_pop(L, 1);
Christopher Fauletc404f112020-02-26 15:03:09 +010012082 if (lua_getfield(L, -1, "tcp_payload") == LUA_TFUNCTION)
12083 hlua_flt_ops->tcp_payload = hlua_filter_tcp_payload;
12084 lua_pop(L, 1);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012085
12086 /* Get id and flags of the filter class */
12087 if (lua_getfield(L, -1, "id") == LUA_TSTRING)
12088 flt_id = lua_tostring(L, -1);
12089 lua_pop(L, 1);
12090 if (lua_getfield(L, -1, "flags") == LUA_TNUMBER)
12091 flt_flags = lua_tointeger(L, -1);
12092 lua_pop(L, 1);
12093
12094 /* Create the filter config */
12095 conf = calloc(1, sizeof(*conf));
Christopher Fauletc86bb872021-08-13 08:33:57 +020012096 if (!conf)
Christopher Faulet69c581a2021-05-31 08:54:04 +020012097 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012098 conf->reg = reg_flt;
12099
12100 /* duplicate args */
12101 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++);
12102 conf->args = calloc(pos + 1, sizeof(*conf->args));
Christopher Fauletc86bb872021-08-13 08:33:57 +020012103 if (!conf->args)
12104 goto error;
12105 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020012106 conf->args[pos] = strdup(args[*cur_arg + 1 + pos]);
Christopher Fauletc86bb872021-08-13 08:33:57 +020012107 if (!conf->args[pos])
12108 goto error;
12109 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020012110 conf->args[pos] = NULL;
12111 *cur_arg += pos + 1;
12112
Christopher Fauletc86bb872021-08-13 08:33:57 +020012113 if (flt_id) {
12114 fconf->id = strdup(flt_id);
12115 if (!fconf->id)
12116 goto error;
12117 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020012118 fconf->flags = flt_flags;
12119 fconf->conf = conf;
12120 fconf->ops = hlua_flt_ops;
12121
12122 lua_settop(L, 0);
12123 return 0;
12124
12125 error:
Christopher Fauletc86bb872021-08-13 08:33:57 +020012126 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012127 free(hlua_flt_ops);
Christopher Fauletc86bb872021-08-13 08:33:57 +020012128 if (conf && conf->args) {
12129 for (pos = 0; conf->args[pos]; pos++)
12130 free(conf->args[pos]);
12131 free(conf->args);
12132 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020012133 free(conf);
Christopher Fauletc86bb872021-08-13 08:33:57 +020012134 free((char *)fconf->id);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012135 lua_settop(L, 0);
12136 return -1;
12137}
12138
Christopher Fauletc404f112020-02-26 15:03:09 +010012139__LJMP static int hlua_register_data_filter(lua_State *L)
12140{
12141 struct filter *filter;
12142 struct channel *chn;
12143
12144 MAY_LJMP(check_args(L, 2, "register_data_filter"));
12145 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
12146 chn = MAY_LJMP(hlua_checkchannel(L, 2));
12147
12148 lua_getfield(L, 1, "__filter");
12149 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
12150 filter = lua_touserdata (L, -1);
12151 lua_pop(L, 1);
12152
12153 register_data_filter(chn_strm(chn), chn, filter);
12154 return 1;
12155}
12156
12157__LJMP static int hlua_unregister_data_filter(lua_State *L)
12158{
12159 struct filter *filter;
12160 struct channel *chn;
12161
12162 MAY_LJMP(check_args(L, 2, "unregister_data_filter"));
12163 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
12164 chn = MAY_LJMP(hlua_checkchannel(L, 2));
12165
12166 lua_getfield(L, 1, "__filter");
12167 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
12168 filter = lua_touserdata (L, -1);
12169 lua_pop(L, 1);
12170
12171 unregister_data_filter(chn_strm(chn), chn, filter);
12172 return 1;
12173}
12174
Christopher Faulet69c581a2021-05-31 08:54:04 +020012175/* This function is an LUA binding used for registering a filter. It expects a
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050012176 * filter name used in the haproxy configuration file and a LUA function to
Christopher Faulet69c581a2021-05-31 08:54:04 +020012177 * parse configuration arguments.
12178 */
12179__LJMP static int hlua_register_filter(lua_State *L)
12180{
12181 struct buffer *trash;
12182 struct flt_kw_list *fkl;
12183 struct flt_kw *fkw;
12184 const char *name;
12185 struct hlua_reg_filter *reg_flt= NULL;
12186 int flt_ref, fun_ref;
12187 int len;
12188
12189 MAY_LJMP(check_args(L, 3, "register_filter"));
12190
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010012191 if (hlua_gethlua(L)) {
12192 /* runtime processing */
12193 WILL_LJMP(luaL_error(L, "register_filter: not available outside of body context"));
12194 }
12195
Christopher Faulet69c581a2021-05-31 08:54:04 +020012196 /* First argument : filter name. */
12197 name = MAY_LJMP(luaL_checkstring(L, 1));
12198
12199 /* Second argument : The filter class */
12200 flt_ref = MAY_LJMP(hlua_checktable(L, 2));
12201
12202 /* Third argument : lua function. */
12203 fun_ref = MAY_LJMP(hlua_checkfunction(L, 3));
12204
12205 trash = get_trash_chunk();
12206 chunk_printf(trash, "lua.%s", name);
12207 fkw = flt_find_kw(trash->area);
12208 if (fkw != NULL) {
12209 reg_flt = fkw->private;
12210 if (reg_flt->flt_ref[hlua_state_id] != -1 || reg_flt->fun_ref[hlua_state_id] != -1) {
12211 ha_warning("Trying to register filter 'lua.%s' more than once. "
12212 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010012213 if (reg_flt->flt_ref[hlua_state_id] != -1)
12214 hlua_unref(L, reg_flt->flt_ref[hlua_state_id]);
12215 if (reg_flt->fun_ref[hlua_state_id] != -1)
12216 hlua_unref(L, reg_flt->fun_ref[hlua_state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012217 }
12218 reg_flt->flt_ref[hlua_state_id] = flt_ref;
12219 reg_flt->fun_ref[hlua_state_id] = fun_ref;
12220 return 0;
12221 }
12222
12223 fkl = calloc(1, sizeof(*fkl) + sizeof(struct flt_kw) * 2);
12224 if (!fkl)
12225 goto alloc_error;
12226 fkl->scope = "HLUA";
12227
12228 reg_flt = new_hlua_reg_filter(name);
12229 if (!reg_flt)
12230 goto alloc_error;
12231
12232 reg_flt->flt_ref[hlua_state_id] = flt_ref;
12233 reg_flt->fun_ref[hlua_state_id] = fun_ref;
12234
12235 /* The filter keyword */
12236 len = strlen("lua.") + strlen(name) + 1;
12237 fkl->kw[0].kw = calloc(1, len);
12238 if (!fkl->kw[0].kw)
12239 goto alloc_error;
12240
12241 snprintf((char *)fkl->kw[0].kw, len, "lua.%s", name);
12242
12243 fkl->kw[0].parse = hlua_filter_parse_fct;
12244 fkl->kw[0].private = reg_flt;
12245 memset(&fkl->kw[1], 0, sizeof(*fkl->kw));
12246
12247 /* Register this new filter */
12248 flt_register_keywords(fkl);
12249
12250 return 0;
12251
12252 alloc_error:
12253 release_hlua_reg_filter(reg_flt);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010012254 hlua_unref(L, flt_ref);
12255 hlua_unref(L, fun_ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012256 ha_free(&fkl);
12257 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
12258 return 0; /* Never reached */
12259}
12260
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012261static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012262 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012263 char **err, unsigned int *timeout)
12264{
12265 const char *error;
12266
12267 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +020012268 if (error == PARSE_TIME_OVER) {
12269 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
12270 args[1], args[0]);
12271 return -1;
12272 }
12273 else if (error == PARSE_TIME_UNDER) {
12274 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
12275 args[1], args[0]);
12276 return -1;
12277 }
12278 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012279 memprintf(err, "%s: invalid timeout", args[0]);
12280 return -1;
12281 }
12282 return 0;
12283}
12284
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +020012285static int hlua_burst_timeout(char **args, int section_type, struct proxy *curpx,
12286 const struct proxy *defpx, const char *file, int line,
12287 char **err)
12288{
12289 return hlua_read_timeout(args, section_type, curpx, defpx,
12290 file, line, err, &hlua_timeout_burst);
12291}
12292
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012293static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012294 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012295 char **err)
12296{
12297 return hlua_read_timeout(args, section_type, curpx, defpx,
12298 file, line, err, &hlua_timeout_session);
12299}
12300
12301static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012302 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012303 char **err)
12304{
12305 return hlua_read_timeout(args, section_type, curpx, defpx,
12306 file, line, err, &hlua_timeout_task);
12307}
12308
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012309static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012310 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012311 char **err)
12312{
12313 return hlua_read_timeout(args, section_type, curpx, defpx,
12314 file, line, err, &hlua_timeout_applet);
12315}
12316
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010012317static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012318 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010012319 char **err)
12320{
12321 char *error;
12322
12323 hlua_nb_instruction = strtoll(args[1], &error, 10);
12324 if (*error != '\0') {
12325 memprintf(err, "%s: invalid number", args[0]);
12326 return -1;
12327 }
12328 return 0;
12329}
12330
Willy Tarreau32f61e22015-03-18 17:54:59 +010012331static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012332 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +010012333 char **err)
12334{
12335 char *error;
12336
12337 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012338 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).", args[0]);
Willy Tarreau32f61e22015-03-18 17:54:59 +010012339 return -1;
12340 }
12341 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
12342 if (*error != '\0') {
12343 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
12344 return -1;
12345 }
12346 return 0;
12347}
12348
12349
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012350/* This function is called by the main configuration key "lua-load". It loads and
12351 * execute an lua file during the parsing of the HAProxy configuration file. It is
12352 * the main lua entry point.
12353 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012354 * This function runs with the HAProxy keywords API. It returns -1 if an error
12355 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012356 *
12357 * In some error case, LUA set an error message in top of the stack. This function
12358 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012359 *
12360 * This function can fail with an abort() due to an Lua critical error.
12361 * We are in the configuration parsing process of HAProxy, this abort() is
12362 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012363 */
Thierry Fournierae6b5682022-09-19 09:04:16 +020012364static int hlua_load_state(char **args, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012365{
12366 int error;
Thierry Fournierae6b5682022-09-19 09:04:16 +020012367 int nargs;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012368
12369 /* Just load and compile the file. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020012370 error = luaL_loadfile(L, args[0]);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012371 if (error) {
Thierry Fournierae6b5682022-09-19 09:04:16 +020012372 memprintf(err, "error in Lua file '%s': %s", args[0], lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012373 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012374 return -1;
12375 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020012376
12377 /* Push args in the Lua stack, except the first one which is the filename */
12378 for (nargs = 1; *(args[nargs]) != 0; nargs++) {
Aurelien DARRAGON4d7aefe2022-09-23 10:22:14 +020012379 /* Check stack size. */
12380 if (!lua_checkstack(L, 1)) {
12381 memprintf(err, "Lua runtime error while loading arguments: stack is full.");
12382 return -1;
12383 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020012384 lua_pushstring(L, args[nargs]);
12385 }
12386 nargs--;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012387
12388 /* If no syntax error where detected, execute the code. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020012389 error = lua_pcall(L, nargs, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012390 switch (error) {
12391 case LUA_OK:
12392 break;
12393 case LUA_ERRRUN:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012394 memprintf(err, "Lua runtime error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012395 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012396 return -1;
12397 case LUA_ERRMEM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012398 memprintf(err, "Lua out of memory error");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012399 return -1;
12400 case LUA_ERRERR:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012401 memprintf(err, "Lua message handler error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012402 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012403 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020012404#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012405 case LUA_ERRGCMM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012406 memprintf(err, "Lua garbage collector error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012407 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012408 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020012409#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012410 default:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012411 memprintf(err, "Lua unknown error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012412 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012413 return -1;
12414 }
12415
12416 return 0;
12417}
12418
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012419static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012420 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012421 char **err)
12422{
12423 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012424 memprintf(err, "'%s' expects a file name as parameter.", args[0]);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012425 return -1;
12426 }
12427
Thierry Fournier59f11be2020-11-29 00:37:41 +010012428 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +010012429 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012430 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020012431 return hlua_load_state(&args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012432}
12433
Thierry Fournier59f11be2020-11-29 00:37:41 +010012434static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012435 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +010012436 char **err)
12437{
12438 int len;
Thierry Fournierae6b5682022-09-19 09:04:16 +020012439 int i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012440
12441 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012442 memprintf(err, "'%s' expects a file as parameter.", args[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012443 return -1;
12444 }
12445
12446 if (per_thread_load == NULL) {
12447 /* allocate the first entry large enough to store the final NULL */
12448 per_thread_load = calloc(1, sizeof(*per_thread_load));
12449 if (per_thread_load == NULL) {
12450 memprintf(err, "out of memory error");
12451 return -1;
12452 }
12453 }
12454
12455 /* count used entries */
12456 for (len = 0; per_thread_load[len] != NULL; len++)
12457 ;
12458
12459 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
12460 if (per_thread_load == NULL) {
12461 memprintf(err, "out of memory error");
12462 return -1;
12463 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010012464 per_thread_load[len + 1] = NULL;
12465
Thierry Fournierae6b5682022-09-19 09:04:16 +020012466 /* count args excepting the first, allocate array and copy args */
12467 for (i = 0; *(args[i + 1]) != 0; i++);
Aurelien DARRAGONb12d1692022-09-23 08:48:34 +020012468 per_thread_load[len] = calloc(i + 1, sizeof(*per_thread_load[len]));
Thierry Fournier59f11be2020-11-29 00:37:41 +010012469 if (per_thread_load[len] == NULL) {
12470 memprintf(err, "out of memory error");
12471 return -1;
12472 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020012473 for (i = 1; *(args[i]) != 0; i++) {
12474 per_thread_load[len][i - 1] = strdup(args[i]);
12475 if (per_thread_load[len][i - 1] == NULL) {
12476 memprintf(err, "out of memory error");
12477 return -1;
12478 }
12479 }
12480 per_thread_load[len][i - 1] = strdup("");
12481 if (per_thread_load[len][i - 1] == NULL) {
12482 memprintf(err, "out of memory error");
12483 return -1;
12484 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010012485
12486 /* loading for thread 1 only */
12487 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012488 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020012489 return hlua_load_state(per_thread_load[len], hlua_states[1], err);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012490}
12491
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010012492/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
12493 * in the given <ctx>.
12494 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +010012495static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010012496{
Thierry Fournier3fb9e512020-11-28 10:13:12 +010012497 lua_getglobal(L, "package"); /* push package variable */
12498 lua_pushstring(L, path); /* push given path */
12499 lua_pushstring(L, ";"); /* push semicolon */
12500 lua_getfield(L, -3, type); /* push old path */
12501 lua_concat(L, 3); /* concatenate to new path */
12502 lua_setfield(L, -2, type); /* store new path */
12503 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010012504
12505 return 0;
12506}
12507
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012508static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012509 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012510 char **err)
12511{
12512 char *path;
12513 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012514 struct prepend_path *p = NULL;
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000012515 size_t i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012516
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012517 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012518 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012519 }
12520
12521 if (!(*args[1])) {
12522 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012523 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012524 }
12525 path = args[1];
12526
12527 if (*args[2]) {
12528 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
12529 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012530 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012531 }
12532 type = args[2];
12533 }
12534
Thierry Fournier59f11be2020-11-29 00:37:41 +010012535 p = calloc(1, sizeof(*p));
12536 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010012537 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012538 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012539 }
12540 p->path = strdup(path);
12541 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010012542 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012543 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012544 }
12545 p->type = strdup(type);
12546 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010012547 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012548 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012549 }
Willy Tarreau2b718102021-04-21 07:32:39 +020012550 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012551
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020012552 /* Handle the global state and the per-thread state for the first
12553 * thread. The remaining threads will be initialized based on
12554 * prepend_path_list.
12555 */
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000012556 for (i = 0; i < 2; i++) {
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020012557 lua_State *L = hlua_states[i];
12558 const char *error;
12559
12560 if (setjmp(safe_ljmp_env) != 0) {
12561 lua_atpanic(L, hlua_panic_safe);
12562 if (lua_type(L, -1) == LUA_TSTRING)
12563 error = lua_tostring(L, -1);
12564 else
12565 error = "critical error";
12566 fprintf(stderr, "lua-prepend-path: %s.\n", error);
12567 exit(1);
12568 } else {
12569 lua_atpanic(L, hlua_panic_ljmp);
12570 }
12571
12572 hlua_prepend_path(L, type, path);
12573
12574 lua_atpanic(L, hlua_panic_safe);
12575 }
12576
Thierry Fournier59f11be2020-11-29 00:37:41 +010012577 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012578
12579err2:
12580 free(p->type);
12581 free(p->path);
12582err:
12583 free(p);
12584 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012585}
12586
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012587/* configuration keywords declaration */
12588static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012589 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012590 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +010012591 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012592 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
12593 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +020012594 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +020012595 { CFG_GLOBAL, "tune.lua.burst-timeout", hlua_burst_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010012596 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +010012597 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012598 { 0, NULL, NULL },
12599}};
12600
Willy Tarreau0108d902018-11-25 19:14:37 +010012601INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
12602
William Lallemand52139182022-03-30 15:05:42 +020012603#ifdef USE_OPENSSL
Christopher Fauletafd8f102018-11-08 11:34:21 +010012604
William Lallemand30fcca12022-03-30 12:03:12 +020012605/*
12606 * This function replace a ckch_store by another one, and rebuild the ckch_inst and all its dependencies.
12607 * It does the sam as "cli_io_handler_commit_cert" but for lua, the major
12608 * difference is that the yield in lua and for the CLI is not handled the same
12609 * way.
12610 */
12611__LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext ctx)
12612{
12613 struct ckch_inst **lua_ckchi = lua_touserdata(L, -1);
12614 struct ckch_store **lua_ckchs = lua_touserdata(L, -2);
12615 struct ckch_inst *ckchi = *lua_ckchi;
12616 struct ckch_store *old_ckchs = lua_ckchs[0];
12617 struct ckch_store *new_ckchs = lua_ckchs[1];
12618 struct hlua *hlua;
12619 char *err = NULL;
12620 int y = 1;
12621
12622 hlua = hlua_gethlua(L);
12623
12624 /* get the first ckchi to copy */
12625 if (ckchi == NULL)
12626 ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
12627
12628 /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
12629 list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
12630 struct ckch_inst *new_inst;
12631
12632 /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
12633 if (y % 10 == 0) {
12634
12635 *lua_ckchi = ckchi;
12636
12637 task_wakeup(hlua->task, TASK_WOKEN_MSG);
12638 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
12639 }
12640
12641 if (ckch_inst_rebuild(new_ckchs, ckchi, &new_inst, &err))
12642 goto error;
12643
12644 /* link the new ckch_inst to the duplicate */
12645 LIST_APPEND(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
12646 y++;
12647 }
12648
12649 /* The generation is finished, we can insert everything */
12650 ckch_store_replace(old_ckchs, new_ckchs);
12651
12652 lua_pop(L, 2); /* pop the lua_ckchs and ckchi */
12653
12654 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
12655
12656 return 0;
12657
12658error:
12659 ckch_store_free(new_ckchs);
12660 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
12661 WILL_LJMP(luaL_error(L, "%s", err));
12662 free(err);
12663
12664 return 0;
12665}
12666
12667/*
12668 * Replace a ckch_store <filename> in the ckchs_tree with a ckch_store created
12669 * from the table in parameter.
12670 *
12671 * This is equivalent to "set ssl cert" + "commit ssl cert" over the CLI, which
12672 * means it does not need to have a transaction since everything is done in the
12673 * same function.
12674 *
12675 * CertCache.set{filename="", crt="", key="", sctl="", ocsp="", issuer=""}
12676 *
12677 */
12678__LJMP static int hlua_ckch_set(lua_State *L)
12679{
12680 struct hlua *hlua;
12681 struct ckch_inst **lua_ckchi;
12682 struct ckch_store **lua_ckchs;
12683 struct ckch_store *old_ckchs = NULL;
12684 struct ckch_store *new_ckchs = NULL;
12685 int errcode = 0;
12686 char *err = NULL;
12687 struct cert_exts *cert_ext = NULL;
12688 char *filename;
William Lallemand52ddd992022-11-22 11:51:53 +010012689 struct ckch_data *data;
William Lallemand30fcca12022-03-30 12:03:12 +020012690 int ret;
12691
12692 if (lua_type(L, -1) != LUA_TTABLE)
12693 WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
12694
12695 hlua = hlua_gethlua(L);
12696
12697 /* FIXME: this should not return an error but should come back later */
12698 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
12699 WILL_LJMP(luaL_error(L, "CertCache already under lock"));
12700
12701 ret = lua_getfield(L, -1, "filename");
12702 if (ret != LUA_TSTRING) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012703 memprintf(&err, "%sNo filename specified!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020012704 errcode |= ERR_ALERT | ERR_FATAL;
12705 goto end;
12706 }
12707 filename = (char *)lua_tostring(L, -1);
12708
12709
12710 /* look for the filename in the tree */
12711 old_ckchs = ckchs_lookup(filename);
12712 if (!old_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012713 memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020012714 errcode |= ERR_ALERT | ERR_FATAL;
12715 goto end;
12716 }
12717 /* TODO: handle extra_files_noext */
12718
12719 new_ckchs = ckchs_dup(old_ckchs);
12720 if (!new_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012721 memprintf(&err, "%sCannot allocate memory!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020012722 errcode |= ERR_ALERT | ERR_FATAL;
12723 goto end;
12724 }
12725
William Lallemand52ddd992022-11-22 11:51:53 +010012726 data = new_ckchs->data;
William Lallemand30fcca12022-03-30 12:03:12 +020012727
12728 /* loop on the field in the table, which have the same name as the
12729 * possible extensions of files */
12730 lua_pushnil(L);
12731 while (lua_next(L, 1)) {
12732 int i;
12733 const char *field = lua_tostring(L, -2);
12734 char *payload = (char *)lua_tostring(L, -1);
12735
12736 if (!field || strcmp(field, "filename") == 0) {
12737 lua_pop(L, 1);
12738 continue;
12739 }
12740
12741 for (i = 0; field && cert_exts[i].ext != NULL; i++) {
12742 if (strcmp(field, cert_exts[i].ext) == 0) {
12743 cert_ext = &cert_exts[i];
12744 break;
12745 }
12746 }
12747
12748 /* this is the default type, the field is not supported */
12749 if (cert_ext == NULL) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012750 memprintf(&err, "%sUnsupported field '%s'", err ? err : "", field);
William Lallemand30fcca12022-03-30 12:03:12 +020012751 errcode |= ERR_ALERT | ERR_FATAL;
12752 goto end;
12753 }
12754
12755 /* appply the change on the duplicate */
William Lallemand52ddd992022-11-22 11:51:53 +010012756 if (cert_ext->load(filename, payload, data, &err) != 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012757 memprintf(&err, "%sCan't load the payload for '%s'", err ? err : "", cert_ext->ext);
William Lallemand30fcca12022-03-30 12:03:12 +020012758 errcode |= ERR_ALERT | ERR_FATAL;
12759 goto end;
12760 }
12761 lua_pop(L, 1);
12762 }
12763
12764 /* store the pointers on the lua stack */
12765 lua_ckchs = lua_newuserdata(L, sizeof(struct ckch_store *) * 2);
12766 lua_ckchs[0] = old_ckchs;
12767 lua_ckchs[1] = new_ckchs;
12768 lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
12769 *lua_ckchi = NULL;
12770
12771 task_wakeup(hlua->task, TASK_WOKEN_MSG);
12772 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
12773
12774end:
12775 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
12776
12777 if (errcode & ERR_CODE) {
12778 ckch_store_free(new_ckchs);
12779 WILL_LJMP(luaL_error(L, "%s", err));
12780 }
12781 free(err);
12782
12783 return 0;
12784}
12785
William Lallemand52139182022-03-30 15:05:42 +020012786#else
12787
12788__LJMP static int hlua_ckch_set(lua_State *L)
12789{
12790 WILL_LJMP(luaL_error(L, "'CertCache.set' needs an HAProxy built with OpenSSL"));
12791
12792 return 0;
12793}
12794#endif /* ! USE_OPENSSL */
12795
12796
12797
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012798/* This function can fail with an abort() due to an Lua critical error.
12799 * We are in the initialisation process of HAProxy, this abort() is
12800 * tolerated.
12801 */
Thierry Fournierb8cef172020-11-28 15:37:17 +010012802int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012803{
12804 struct hlua_init_function *init;
12805 const char *msg;
12806 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +010012807 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +010012808 const char *kind;
12809 const char *trace;
12810 int return_status = 1;
12811#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
12812 int nres;
12813#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012814
Willy Tarreaucdb53462020-12-02 12:12:00 +010012815 /* disable memory limit checks if limit is not set */
12816 if (!hlua_global_allocator.limit)
12817 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
12818
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050012819 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +010012820 if (setjmp(safe_ljmp_env) != 0) {
12821 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +010012822 if (lua_type(L, -1) == LUA_TSTRING)
12823 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010012824 else
12825 error = "critical error";
12826 fprintf(stderr, "Lua post-init: %s.\n", error);
12827 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010012828 } else {
12829 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010012830 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +020012831
Thierry Fournierc7492592020-11-28 23:57:24 +010012832 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010012833 hlua_pushref(L, init->function_ref);
Aurelien DARRAGON16d047b2023-03-20 16:29:55 +010012834 /* function ref should be released right away since it was pushed
12835 * on the stack and will not be used anymore
12836 */
12837 hlua_unref(L, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +010012838
12839#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +010012840 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +010012841#else
Thierry Fournierb8cef172020-11-28 15:37:17 +010012842 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +010012843#endif
12844 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012845 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +010012846
12847 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +010012848 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +010012849 break;
Thierry Fournier670db242020-11-28 10:49:59 +010012850
12851 case LUA_ERRERR:
12852 kind = "message handler error";
Willy Tarreau14de3952022-11-14 07:08:28 +010012853 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010012854 case LUA_ERRRUN:
12855 if (!kind)
12856 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010012857 msg = lua_tostring(L, -1);
12858 lua_settop(L, 0); /* Empty the stack. */
Christopher Fauletd09cc512021-03-24 14:48:45 +010012859 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010012860 if (msg)
12861 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
12862 else
12863 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
12864 return_status = 0;
12865 break;
12866
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012867 default:
Thierry Fournier670db242020-11-28 10:49:59 +010012868 /* Unknown error */
12869 kind = "Unknown error";
Willy Tarreau14de3952022-11-14 07:08:28 +010012870 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010012871 case LUA_YIELD:
12872 /* yield is not configured at this step, this state doesn't happen */
12873 if (!kind)
12874 kind = "yield not allowed";
Willy Tarreau14de3952022-11-14 07:08:28 +010012875 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010012876 case LUA_ERRMEM:
12877 if (!kind)
12878 kind = "out of memory error";
Aurelien DARRAGON3e81aed2023-08-09 10:11:49 +020012879 lua_settop(L, 0); /* Empty the stack. */
Christopher Fauletd09cc512021-03-24 14:48:45 +010012880 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010012881 ha_alert("Lua init: %s: %s\n", kind, trace);
12882 return_status = 0;
12883 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012884 }
Thierry Fournier670db242020-11-28 10:49:59 +010012885 if (!return_status)
12886 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012887 }
Thierry Fournier3c539322020-11-28 16:05:05 +010012888
12889 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +010012890 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012891}
12892
Thierry Fournierb8cef172020-11-28 15:37:17 +010012893int hlua_post_init()
12894{
Thierry Fournier59f11be2020-11-29 00:37:41 +010012895 int ret;
12896 int i;
12897 int errors;
12898 char *err = NULL;
12899 struct hlua_function *fcn;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012900 struct hlua_reg_filter *reg_flt;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012901
Willy Tarreaub1310492021-08-30 09:35:18 +020012902#if defined(USE_OPENSSL)
Thierry Fournierb8cef172020-11-28 15:37:17 +010012903 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012904 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010012905 int saved_used_backed = global.ssl_used_backend;
12906 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012907 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +010012908 global.ssl_used_backend = saved_used_backed;
12909 }
12910#endif
12911
Thierry Fournierc7492592020-11-28 23:57:24 +010012912 /* Perform post init of common thread */
12913 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012914 ha_set_thread(&ha_thread_info[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012915 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
12916 if (ret == 0)
12917 return 0;
12918
12919 /* init remaining lua states and load files */
12920 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
12921
12922 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012923 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012924
12925 /* Init lua state */
12926 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
12927
12928 /* Load lua files */
12929 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
12930 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
12931 if (ret != 0) {
12932 ha_alert("Lua init: %s\n", err);
12933 return 0;
12934 }
12935 }
12936 }
12937
12938 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012939 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012940
12941 /* Execute post init for all states */
12942 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
12943
12944 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012945 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012946
12947 /* run post init */
12948 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
12949 if (ret == 0)
12950 return 0;
12951 }
12952
12953 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012954 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012955
12956 /* control functions registering. Each function must have:
12957 * - only the function_ref[0] set positive and all other to -1
12958 * - only the function_ref[0] set to -1 and all other positive
12959 * This ensure a same reference is not used both in shared
12960 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050012961 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +010012962 * complicated to found for the end user.
12963 */
12964 errors = 0;
12965 list_for_each_entry(fcn, &referenced_functions, l) {
12966 ret = 0;
12967 for (i = 1; i < global.nbthread + 1; i++) {
12968 if (fcn->function_ref[i] == -1)
12969 ret--;
12970 else
12971 ret++;
12972 }
12973 if (abs(ret) != global.nbthread) {
12974 ha_alert("Lua function '%s' is not referenced in all thread. "
12975 "Expect function in all thread or in none thread.\n", fcn->name);
12976 errors++;
12977 continue;
12978 }
12979
12980 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050012981 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
12982 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +010012983 "exclusive.\n", fcn->name);
12984 errors++;
12985 }
12986 }
12987
Christopher Faulet69c581a2021-05-31 08:54:04 +020012988 /* Do the same with registered filters */
12989 list_for_each_entry(reg_flt, &referenced_filters, l) {
12990 ret = 0;
12991 for (i = 1; i < global.nbthread + 1; i++) {
12992 if (reg_flt->flt_ref[i] == -1)
12993 ret--;
12994 else
12995 ret++;
12996 }
12997 if (abs(ret) != global.nbthread) {
12998 ha_alert("Lua filter '%s' is not referenced in all thread. "
12999 "Expect function in all thread or in none thread.\n", reg_flt->name);
13000 errors++;
13001 continue;
13002 }
13003
13004 if ((reg_flt->flt_ref[0] == -1) == (ret < 0)) {
13005 ha_alert("Lua filter '%s' is referenced both ins shared Lua context (through lua-load) "
13006 "and per-thread Lua context (through lua-load-per-thread). these two context "
13007 "exclusive.\n", fcn->name);
13008 errors++;
13009 }
13010 }
13011
13012
Thierry Fournier59f11be2020-11-29 00:37:41 +010013013 if (errors > 0)
13014 return 0;
13015
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050013016 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +010013017 * -1 in order to have probably a segfault if someone use it
13018 */
13019 hlua_state_id = -1;
13020
13021 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +010013022}
13023
Willy Tarreau32f61e22015-03-18 17:54:59 +010013024/* The memory allocator used by the Lua stack. <ud> is a pointer to the
13025 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
13026 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010013027 * allocation. <nsize> is the requested new size. A new allocation is
13028 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +010013029 * zero. This one verifies that the limits are respected but is optimized
13030 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreaua5efdff2021-10-22 16:00:02 +020013031 *
13032 * Warning: while this API ressembles glibc's realloc() a lot, glibc surpasses
13033 * POSIX by making realloc(ptr,0) an effective free(), but others do not do
13034 * that and will simply allocate zero as if it were the result of malloc(0),
13035 * so mapping this onto realloc() will lead to memory leaks on non-glibc
13036 * systems.
Willy Tarreau32f61e22015-03-18 17:54:59 +010013037 */
13038static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
13039{
13040 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +010013041 size_t limit, old, new;
13042
13043 /* a limit of ~0 means unlimited and boot complete, so there's no need
13044 * for accounting anymore.
13045 */
Willy Tarreaua5efdff2021-10-22 16:00:02 +020013046 if (likely(~zone->limit == 0)) {
13047 if (!nsize)
13048 ha_free(&ptr);
13049 else
13050 ptr = realloc(ptr, nsize);
13051 return ptr;
13052 }
Willy Tarreau32f61e22015-03-18 17:54:59 +010013053
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010013054 if (!ptr)
13055 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +010013056
Willy Tarreaucdb53462020-12-02 12:12:00 +010013057 /* enforce strict limits across all threads */
13058 limit = zone->limit;
13059 old = _HA_ATOMIC_LOAD(&zone->allocated);
13060 do {
13061 new = old + nsize - osize;
13062 if (unlikely(nsize && limit && new > limit))
13063 return NULL;
13064 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +010013065
Willy Tarreaua5efdff2021-10-22 16:00:02 +020013066 if (!nsize)
13067 ha_free(&ptr);
13068 else
13069 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +010013070
13071 if (unlikely(!ptr && nsize)) // failed
13072 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
13073
13074 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +010013075 return ptr;
13076}
13077
Thierry Fournierecb83c22020-11-28 15:49:44 +010013078/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020013079 * We are in the initialisation process of HAProxy, this abort() is
13080 * tolerated.
13081 */
Thierry Fournierecb83c22020-11-28 15:49:44 +010013082lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010013083{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013084 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013085 int idx;
13086 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013087 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013088 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +010013089 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +010013090 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013091 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +010013092 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013093
Thierry FOURNIER380d0932015-01-23 14:27:52 +010013094 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013095 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +010013096
firexinghe64d7afb2023-07-13 11:03:34 +080013097 if (!L) {
13098 fprintf(stderr,
13099 "Lua init: critical error: lua_newstate() returned NULL."
13100 " This may possibly be caused by a memory allocation error.\n");
13101 exit(1);
13102 }
13103
Thierry Fournier4234dbd2020-11-28 13:18:23 +010013104 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013105 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +010013106 *context = NULL;
13107
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080013108 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +020013109 * the Lua function can fail with an abort. We are in the initialisation
13110 * process of HAProxy, this abort() is tolerated.
13111 */
13112
Thierry Fournier3c539322020-11-28 16:05:05 +010013113 /* Call post initialisation function in safe environment. */
13114 if (setjmp(safe_ljmp_env) != 0) {
13115 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013116 if (lua_type(L, -1) == LUA_TSTRING)
13117 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010013118 else
13119 error_msg = "critical error";
13120 fprintf(stderr, "Lua init: %s.\n", error_msg);
13121 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010013122 } else {
13123 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010013124 }
13125
Thierry FOURNIER380d0932015-01-23 14:27:52 +010013126 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013127 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010013128#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
13129#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
13130#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013131 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010013132#endif
13133#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013134 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010013135#endif
13136#undef HLUA_PREPEND_PATH_TOSTRING
13137#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013138
Thierry Fournier59f11be2020-11-29 00:37:41 +010013139 /* Apply configured prepend path */
13140 list_for_each_entry(pp, &prepend_path_list, l)
13141 hlua_prepend_path(L, pp->type, pp->path);
13142
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013143 /*
Aurelien DARRAGON8cd620b2023-04-07 17:37:46 +020013144 * Override some lua functions.
13145 *
13146 */
13147
13148 /* push our "safe" coroutine.create() function */
13149 lua_getglobal(L, "coroutine");
13150 lua_pushcclosure(L, hlua_coroutine_create, 0);
13151 lua_setfield(L, -2, "create");
13152
13153 /*
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013154 *
13155 * Create "core" object.
13156 *
13157 */
13158
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +010013159 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013160 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013161
Thierry Fournierecb83c22020-11-28 15:49:44 +010013162 /* set the thread id */
13163 hlua_class_const_int(L, "thread", thread_num);
13164
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013165 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +010013166 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013167 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013168
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010013169 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013170 hlua_class_function(L, "register_init", hlua_register_init);
13171 hlua_class_function(L, "register_task", hlua_register_task);
13172 hlua_class_function(L, "register_fetches", hlua_register_fetches);
13173 hlua_class_function(L, "register_converters", hlua_register_converters);
13174 hlua_class_function(L, "register_action", hlua_register_action);
13175 hlua_class_function(L, "register_service", hlua_register_service);
13176 hlua_class_function(L, "register_cli", hlua_register_cli);
Christopher Faulet69c581a2021-05-31 08:54:04 +020013177 hlua_class_function(L, "register_filter", hlua_register_filter);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013178 hlua_class_function(L, "yield", hlua_yield);
13179 hlua_class_function(L, "set_nice", hlua_set_nice);
13180 hlua_class_function(L, "sleep", hlua_sleep);
13181 hlua_class_function(L, "msleep", hlua_msleep);
13182 hlua_class_function(L, "add_acl", hlua_add_acl);
13183 hlua_class_function(L, "del_acl", hlua_del_acl);
13184 hlua_class_function(L, "set_map", hlua_set_map);
13185 hlua_class_function(L, "del_map", hlua_del_map);
13186 hlua_class_function(L, "tcp", hlua_socket_new);
William Lallemand3956c4e2021-09-21 16:25:15 +020013187 hlua_class_function(L, "httpclient", hlua_httpclient_new);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +010013188 hlua_class_function(L, "event_sub", hlua_event_global_sub);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013189 hlua_class_function(L, "log", hlua_log);
13190 hlua_class_function(L, "Debug", hlua_log_debug);
13191 hlua_class_function(L, "Info", hlua_log_info);
13192 hlua_class_function(L, "Warning", hlua_log_warning);
13193 hlua_class_function(L, "Alert", hlua_log_alert);
13194 hlua_class_function(L, "done", hlua_done);
Aurelien DARRAGON5bed48f2023-04-21 17:32:46 +020013195 hlua_class_function(L, "disable_legacy_mailers", hlua_disable_legacy_mailers);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013196 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010013197
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013198 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013199
13200 /*
13201 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013202 * Create "act" object.
13203 *
13204 */
13205
13206 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013207 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013208
13209 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013210 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
13211 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
13212 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
13213 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
13214 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
13215 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
13216 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
13217 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013218
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013219 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010013220
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013221 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013222
13223 /*
13224 *
Christopher Faulet69c581a2021-05-31 08:54:04 +020013225 * Create "Filter" object.
13226 *
13227 */
13228
13229 /* This table entry is the object "filter" base. */
13230 lua_newtable(L);
13231
13232 /* push flags and constants */
13233 hlua_class_const_int(L, "CONTINUE", 1);
13234 hlua_class_const_int(L, "WAIT", 0);
13235 hlua_class_const_int(L, "ERROR", -1);
13236
13237 hlua_class_const_int(L, "FLT_CFG_FL_HTX", FLT_CFG_FL_HTX);
13238
Christopher Fauletc404f112020-02-26 15:03:09 +010013239 hlua_class_function(L, "wake_time", hlua_set_wake_time);
13240 hlua_class_function(L, "register_data_filter", hlua_register_data_filter);
13241 hlua_class_function(L, "unregister_data_filter", hlua_unregister_data_filter);
13242
Christopher Faulet69c581a2021-05-31 08:54:04 +020013243 lua_setglobal(L, "filter");
13244
13245 /*
13246 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013247 * Register class Map
13248 *
13249 */
13250
13251 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013252 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013253
13254 /* register pattern types. */
13255 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013256 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010013257 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020013258 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013259 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010013260 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013261
13262 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013263 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013264
13265 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013266 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013267
Ilya Shipitsind4259502020-04-08 01:07:56 +050013268 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013269 lua_pushstring(L, "__index");
13270 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013271
13272 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013273 hlua_class_function(L, "lookup", hlua_map_lookup);
13274 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013275
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013276 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013277
Thierry Fournier45e78d72016-02-19 18:34:46 +010013278 /* Register previous table in the registry with reference and named entry.
13279 * The function hlua_register_metatable() pops the stack, so we
13280 * previously create a copy of the table.
13281 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013282 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
13283 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013284
13285 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013286 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013287
13288 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013289 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013290
13291 /*
13292 *
William Lallemand30fcca12022-03-30 12:03:12 +020013293 * Register "CertCache" class
13294 *
13295 */
13296
13297 /* Create and fill the metatable. */
13298 lua_newtable(L);
13299 /* Register */
13300 hlua_class_function(L, "set", hlua_ckch_set);
13301 lua_setglobal(L, CLASS_CERTCACHE); /* Create global object called Regex */
13302
13303 /*
13304 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013305 * Register class Channel
13306 *
13307 */
13308
13309 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013310 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013311
Ilya Shipitsind4259502020-04-08 01:07:56 +050013312 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013313 lua_pushstring(L, "__index");
13314 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013315
13316 /* Register . */
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013317 hlua_class_function(L, "data", hlua_channel_get_data);
13318 hlua_class_function(L, "line", hlua_channel_get_line);
13319 hlua_class_function(L, "set", hlua_channel_set_data);
13320 hlua_class_function(L, "remove", hlua_channel_del_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013321 hlua_class_function(L, "append", hlua_channel_append);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013322 hlua_class_function(L, "prepend", hlua_channel_prepend);
13323 hlua_class_function(L, "insert", hlua_channel_insert_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013324 hlua_class_function(L, "send", hlua_channel_send);
13325 hlua_class_function(L, "forward", hlua_channel_forward);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013326 hlua_class_function(L, "input", hlua_channel_get_in_len);
13327 hlua_class_function(L, "output", hlua_channel_get_out_len);
13328 hlua_class_function(L, "may_recv", hlua_channel_may_recv);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013329 hlua_class_function(L, "is_full", hlua_channel_is_full);
13330 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013331
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013332 /* Deprecated API */
13333 hlua_class_function(L, "get", hlua_channel_get);
13334 hlua_class_function(L, "dup", hlua_channel_dup);
13335 hlua_class_function(L, "getline", hlua_channel_getline);
13336 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
13337 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
13338
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013339 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013340
13341 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013342 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013343
13344 /*
13345 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013346 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013347 *
13348 */
13349
13350 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013351 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013352
Ilya Shipitsind4259502020-04-08 01:07:56 +050013353 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013354 lua_pushstring(L, "__index");
13355 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013356
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013357 /* Browse existing fetches and create the associated
13358 * object method.
13359 */
13360 sf = NULL;
13361 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013362 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
13363 * by an underscore.
13364 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020013365 strlcpy2(trash.area, sf->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020013366 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013367 if (*p == '.' || *p == '-' || *p == '+')
13368 *p = '_';
13369
13370 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013371 lua_pushstring(L, trash.area);
13372 lua_pushlightuserdata(L, sf);
13373 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
13374 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013375 }
13376
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013377 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013378
13379 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013380 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013381
13382 /*
13383 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013384 * Register class Converters
13385 *
13386 */
13387
13388 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013389 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013390
13391 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013392 lua_pushstring(L, "__index");
13393 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013394
13395 /* Browse existing converters and create the associated
13396 * object method.
13397 */
13398 sc = NULL;
13399 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013400 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
13401 * by an underscore.
13402 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020013403 strlcpy2(trash.area, sc->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020013404 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013405 if (*p == '.' || *p == '-' || *p == '+')
13406 *p = '_';
13407
13408 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013409 lua_pushstring(L, trash.area);
13410 lua_pushlightuserdata(L, sc);
13411 lua_pushcclosure(L, hlua_run_sample_conv, 1);
13412 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013413 }
13414
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013415 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013416
13417 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013418 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013419
13420 /*
13421 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013422 * Register class HTTP
13423 *
13424 */
13425
13426 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013427 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013428
Ilya Shipitsind4259502020-04-08 01:07:56 +050013429 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013430 lua_pushstring(L, "__index");
13431 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013432
13433 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013434 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
13435 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
13436 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
13437 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
13438 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
13439 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
13440 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
13441 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
13442 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
13443 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013444
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013445 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
13446 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
13447 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
13448 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
13449 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
13450 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
13451 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013452
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013453 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013454
13455 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013456 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013457
Christopher Fauletdf97ac42020-02-26 16:57:19 +010013458 /*
13459 *
13460 * Register class HTTPMessage
13461 *
13462 */
13463
13464 /* Create and fill the metatable. */
13465 lua_newtable(L);
13466
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050013467 /* Create and fill the __index entry. */
Christopher Fauletdf97ac42020-02-26 16:57:19 +010013468 lua_pushstring(L, "__index");
13469 lua_newtable(L);
13470
13471 /* Register Lua functions. */
13472 hlua_class_function(L, "is_resp", hlua_http_msg_is_resp);
13473 hlua_class_function(L, "get_stline", hlua_http_msg_get_stline);
13474 hlua_class_function(L, "get_headers", hlua_http_msg_get_headers);
13475 hlua_class_function(L, "del_header", hlua_http_msg_del_hdr);
13476 hlua_class_function(L, "rep_header", hlua_http_msg_rep_hdr);
13477 hlua_class_function(L, "rep_value", hlua_http_msg_rep_val);
13478 hlua_class_function(L, "add_header", hlua_http_msg_add_hdr);
13479 hlua_class_function(L, "set_header", hlua_http_msg_set_hdr);
13480 hlua_class_function(L, "set_method", hlua_http_msg_set_meth);
13481 hlua_class_function(L, "set_path", hlua_http_msg_set_path);
13482 hlua_class_function(L, "set_query", hlua_http_msg_set_query);
13483 hlua_class_function(L, "set_uri", hlua_http_msg_set_uri);
13484 hlua_class_function(L, "set_status", hlua_http_msg_set_status);
13485 hlua_class_function(L, "is_full", hlua_http_msg_is_full);
13486 hlua_class_function(L, "may_recv", hlua_http_msg_may_recv);
13487 hlua_class_function(L, "eom", hlua_http_msg_is_eom);
13488 hlua_class_function(L, "input", hlua_http_msg_get_in_len);
13489 hlua_class_function(L, "output", hlua_http_msg_get_out_len);
13490
13491 hlua_class_function(L, "body", hlua_http_msg_get_body);
13492 hlua_class_function(L, "set", hlua_http_msg_set_data);
13493 hlua_class_function(L, "remove", hlua_http_msg_del_data);
13494 hlua_class_function(L, "append", hlua_http_msg_append);
13495 hlua_class_function(L, "prepend", hlua_http_msg_prepend);
13496 hlua_class_function(L, "insert", hlua_http_msg_insert_data);
13497 hlua_class_function(L, "set_eom", hlua_http_msg_set_eom);
13498 hlua_class_function(L, "unset_eom", hlua_http_msg_unset_eom);
13499
13500 hlua_class_function(L, "send", hlua_http_msg_send);
13501 hlua_class_function(L, "forward", hlua_http_msg_forward);
13502
13503 lua_rawset(L, -3);
13504
13505 /* Register previous table in the registry with reference and named entry. */
13506 class_http_msg_ref = hlua_register_metatable(L, CLASS_HTTP_MSG);
William Lallemand3956c4e2021-09-21 16:25:15 +020013507
13508 /*
13509 *
13510 * Register class HTTPClient
13511 *
13512 */
13513
13514 /* Create and fill the metatable. */
13515 lua_newtable(L);
13516 lua_pushstring(L, "__index");
13517 lua_newtable(L);
13518 hlua_class_function(L, "get", hlua_httpclient_get);
William Lallemanddc2cc902021-10-26 11:43:26 +020013519 hlua_class_function(L, "head", hlua_httpclient_head);
13520 hlua_class_function(L, "put", hlua_httpclient_put);
13521 hlua_class_function(L, "post", hlua_httpclient_post);
13522 hlua_class_function(L, "delete", hlua_httpclient_delete);
William Lallemand3956c4e2021-09-21 16:25:15 +020013523 lua_settable(L, -3); /* Sets the __index entry. */
William Lallemandf77f1de2021-09-28 19:10:38 +020013524 /* Register the garbage collector entry. */
13525 lua_pushstring(L, "__gc");
13526 lua_pushcclosure(L, hlua_httpclient_gc, 0);
13527 lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
13528
William Lallemand3956c4e2021-09-21 16:25:15 +020013529
13530
13531 class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013532 /*
13533 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013534 * Register class AppletTCP
13535 *
13536 */
13537
13538 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013539 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013540
Ilya Shipitsind4259502020-04-08 01:07:56 +050013541 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013542 lua_pushstring(L, "__index");
13543 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013544
13545 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013546 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
13547 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
13548 hlua_class_function(L, "send", hlua_applet_tcp_send);
13549 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
13550 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
13551 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
13552 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
13553 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013554
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013555 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013556
13557 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013558 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013559
13560 /*
13561 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013562 * Register class AppletHTTP
13563 *
13564 */
13565
13566 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013567 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013568
Ilya Shipitsind4259502020-04-08 01:07:56 +050013569 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013570 lua_pushstring(L, "__index");
13571 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013572
13573 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013574 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
13575 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
13576 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
13577 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
13578 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
13579 hlua_class_function(L, "getline", hlua_applet_http_getline);
13580 hlua_class_function(L, "receive", hlua_applet_http_recv);
13581 hlua_class_function(L, "send", hlua_applet_http_send);
13582 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
13583 hlua_class_function(L, "set_status", hlua_applet_http_status);
13584 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013585
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013586 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013587
13588 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013589 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013590
13591 /*
13592 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013593 * Register class TXN
13594 *
13595 */
13596
13597 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013598 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013599
Ilya Shipitsind4259502020-04-08 01:07:56 +050013600 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013601 lua_pushstring(L, "__index");
13602 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013603
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010013604 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013605 hlua_class_function(L, "set_priv", hlua_set_priv);
13606 hlua_class_function(L, "get_priv", hlua_get_priv);
13607 hlua_class_function(L, "set_var", hlua_set_var);
13608 hlua_class_function(L, "unset_var", hlua_unset_var);
13609 hlua_class_function(L, "get_var", hlua_get_var);
13610 hlua_class_function(L, "done", hlua_txn_done);
13611 hlua_class_function(L, "reply", hlua_txn_reply_new);
13612 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
13613 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
13614 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
13615 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
13616 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
13617 hlua_class_function(L, "deflog", hlua_txn_deflog);
13618 hlua_class_function(L, "log", hlua_txn_log);
13619 hlua_class_function(L, "Debug", hlua_txn_log_debug);
13620 hlua_class_function(L, "Info", hlua_txn_log_info);
13621 hlua_class_function(L, "Warning", hlua_txn_log_warning);
13622 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010013623
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013624 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013625
13626 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013627 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013628
13629 /*
13630 *
Christopher Faulet700d9e82020-01-31 12:21:52 +010013631 * Register class reply
13632 *
13633 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013634 lua_newtable(L);
13635 lua_pushstring(L, "__index");
13636 lua_newtable(L);
13637 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
13638 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
13639 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
13640 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
13641 lua_settable(L, -3); /* Sets the __index entry. */
13642 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +010013643
13644
13645 /*
13646 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013647 * Register class Socket
13648 *
13649 */
13650
13651 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013652 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013653
Ilya Shipitsind4259502020-04-08 01:07:56 +050013654 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013655 lua_pushstring(L, "__index");
13656 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013657
Baptiste Assmann84bb4932015-03-02 21:40:06 +010013658#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013659 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +010013660#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013661 hlua_class_function(L, "connect", hlua_socket_connect);
13662 hlua_class_function(L, "send", hlua_socket_send);
13663 hlua_class_function(L, "receive", hlua_socket_receive);
13664 hlua_class_function(L, "close", hlua_socket_close);
13665 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
13666 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
13667 hlua_class_function(L, "setoption", hlua_socket_setoption);
13668 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013669
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013670 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013671
13672 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013673 lua_pushstring(L, "__gc");
13674 lua_pushcclosure(L, hlua_socket_gc, 0);
13675 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013676
13677 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013678 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013679
Thierry Fournieraafc7772020-12-04 11:47:47 +010013680 lua_atpanic(L, hlua_panic_safe);
13681
13682 return L;
13683}
13684
13685void hlua_init(void) {
13686 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010013687 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +010013688#ifdef USE_OPENSSL
13689 struct srv_kw *kw;
13690 int tmp_error;
13691 char *error;
13692 char *args[] = { /* SSL client configuration. */
13693 "ssl",
13694 "verify",
13695 "none",
13696 NULL
13697 };
13698#endif
13699
13700 /* Init post init function list head */
13701 for (i = 0; i < MAX_THREADS + 1; i++)
13702 LIST_INIT(&hlua_init_functions[i]);
13703
13704 /* Init state for common/shared lua parts */
13705 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020013706 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010013707 hlua_states[0] = hlua_init_state(0);
13708
13709 /* Init state 1 for thread 0. We have at least one thread. */
13710 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020013711 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010013712 hlua_states[1] = hlua_init_state(1);
13713
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013714 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +020013715 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010013716 if (!socket_proxy) {
13717 fprintf(stderr, "Lua init: %s\n", errmsg);
13718 exit(1);
13719 }
13720 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013721
13722 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013723 socket_tcp = new_server(socket_proxy);
13724 if (!socket_tcp) {
13725 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
13726 exit(1);
13727 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013728
13729#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013730 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013731 socket_ssl = new_server(socket_proxy);
13732 if (!socket_ssl) {
13733 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
13734 exit(1);
13735 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013736
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013737 socket_ssl->use_ssl = 1;
13738 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013739
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000013740 for (i = 0; args[i] != NULL; i++) {
13741 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013742 /*
13743 *
13744 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080013745 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013746 * features like client certificates and ssl_verify.
13747 *
13748 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013749 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013750 if (tmp_error != 0) {
13751 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
13752 abort(); /* This must be never arrives because the command line
13753 not editable by the user. */
13754 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000013755 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013756 }
13757 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013758#endif
Thierry Fournier75933d42016-01-21 09:30:18 +010013759
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010013760}
Willy Tarreaubb57d942016-12-21 19:04:56 +010013761
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020013762static void hlua_deinit()
13763{
Willy Tarreau186f3762020-12-04 11:48:12 +010013764 int thr;
Christopher Faulet69c581a2021-05-31 08:54:04 +020013765 struct hlua_reg_filter *reg_flt, *reg_flt_bck;
13766
13767 list_for_each_entry_safe(reg_flt, reg_flt_bck, &referenced_filters, l)
13768 release_hlua_reg_filter(reg_flt);
Willy Tarreau186f3762020-12-04 11:48:12 +010013769
13770 for (thr = 0; thr < MAX_THREADS+1; thr++) {
13771 if (hlua_states[thr])
13772 lua_close(hlua_states[thr]);
13773 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +010013774
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020013775 srv_drop(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +010013776
Willy Tarreau0f143af2021-03-05 10:41:48 +010013777#ifdef USE_OPENSSL
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020013778 srv_drop(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +010013779#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010013780
13781 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020013782}
13783
13784REGISTER_POST_DEINIT(hlua_deinit);
13785
Willy Tarreau80713382018-11-26 10:19:54 +010013786static void hlua_register_build_options(void)
13787{
Willy Tarreaubb57d942016-12-21 19:04:56 +010013788 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +010013789
Willy Tarreaubb57d942016-12-21 19:04:56 +010013790 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
13791 hap_register_build_opts(ptr, 1);
13792}
Willy Tarreau80713382018-11-26 10:19:54 +010013793
13794INITCALL0(STG_REGISTER, hlua_register_build_options);