blob: f81e20e076fd1d7c8fca9475b10d44bb37d241d4 [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
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008862/* This function is an LUA binding that register LUA function to be
8863 * executed after the HAProxy configuration parsing and before the
8864 * HAProxy scheduler starts. This function expect only one LUA
8865 * argument that is a function. This function returns nothing, but
8866 * throws if an error is encountered.
8867 */
8868__LJMP static int hlua_register_init(lua_State *L)
8869{
8870 struct hlua_init_function *init;
8871 int ref;
8872
8873 MAY_LJMP(check_args(L, 1, "register_init"));
8874
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01008875 if (hlua_gethlua(L)) {
8876 /* runtime processing */
8877 WILL_LJMP(luaL_error(L, "register_init: not available outside of body context"));
8878 }
8879
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008880 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8881
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008882 init = calloc(1, sizeof(*init));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008883 if (!init) {
8884 hlua_unref(L, ref);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008885 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008886 }
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008887
8888 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02008889 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008890 return 0;
8891}
8892
Ilya Shipitsin6f86eaa2022-11-30 16:22:42 +05008893/* This function is an LUA binding. It permits to register a task
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008894 * executed in parallel of the main HAroxy activity. The task is
8895 * created and it is set in the HAProxy scheduler. It can be called
8896 * from the "init" section, "post init" or during the runtime.
8897 *
8898 * Lua prototype:
8899 *
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008900 * <none> core.register_task(<function>[, <arg1>[, <arg2>[, ...[, <arg4>]]]])
8901 *
8902 * <arg1..4> are optional arguments that will be provided to <function>
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008903 */
Aurelien DARRAGONe0b16352023-04-21 17:38:37 +02008904__LJMP static int hlua_register_task(lua_State *L)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008905{
Christopher Faulet5294ec02021-04-12 12:24:47 +02008906 struct hlua *hlua = NULL;
8907 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008908 int ref;
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008909 int nb_arg;
8910 int it;
8911 int arg_ref[4]; /* optional arguments */
Thierry Fournier021d9862020-11-28 23:42:03 +01008912 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008913
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008914 nb_arg = lua_gettop(L);
8915 if (nb_arg < 1)
8916 WILL_LJMP(luaL_error(L, "register_task: <func> argument is required"));
8917 else if (nb_arg > 5)
8918 WILL_LJMP(luaL_error(L, "register_task: no more that 4 optional arguments may be provided"));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008919
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008920 /* first arg: function ref */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008921 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8922
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008923 /* extract optional args (if any) */
8924 it = 0;
8925 while (--nb_arg) {
8926 lua_pushvalue(L, 2 + it);
8927 arg_ref[it] = hlua_ref(L); /* get arg reference */
8928 it += 1;
8929 }
8930 nb_arg = it;
8931
Thierry Fournier75fc0292020-11-28 13:18:56 +01008932 /* Get the reference state. If the reference is NULL, L is the master
8933 * state, otherwise hlua->T is.
8934 */
8935 hlua = hlua_gethlua(L);
8936 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01008937 /* we are in runtime processing */
8938 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008939 else
Thierry Fournier021d9862020-11-28 23:42:03 +01008940 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01008941 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008942
Willy Tarreaubafbe012017-11-24 17:34:44 +01008943 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008944 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008945 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008946 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008947
Thierry Fournier59f11be2020-11-29 00:37:41 +01008948 /* We are in the common lua state, execute the task anywhere,
8949 * otherwise, inherit the current thread identifier
8950 */
8951 if (state_id == 0)
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008952 task = task_new_anywhere();
Thierry Fournier59f11be2020-11-29 00:37:41 +01008953 else
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008954 task = task_new_here();
Willy Tarreaue09101e2018-10-16 17:37:12 +02008955 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008956 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02008957
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008958 task->context = hlua;
8959 task->process = hlua_process_task;
8960
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01008961 if (!hlua_ctx_init(hlua, state_id, task))
Christopher Faulet5294ec02021-04-12 12:24:47 +02008962 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008963
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008964 /* Ensure there is enough space on the stack for the function
8965 * plus optional arguments
8966 */
8967 if (!lua_checkstack(hlua->T, (1 + nb_arg)))
8968 goto alloc_error;
8969
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008970 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01008971 hlua_pushref(hlua->T, ref);
Aurelien DARRAGONbe58d662023-03-13 14:09:21 +01008972 /* function ref not needed anymore since it was pushed to the substack */
8973 hlua_unref(L, ref);
8974
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008975 hlua->nargs = nb_arg;
8976
8977 /* push optional arguments to the function */
8978 for (it = 0; it < nb_arg; it++) {
8979 /* push arg to the stack */
8980 hlua_pushref(hlua->T, arg_ref[it]);
8981 /* arg ref not needed anymore since it was pushed to the substack */
8982 hlua_unref(L, arg_ref[it]);
8983 }
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008984
8985 /* Schedule task. */
Willy Tarreaue3957f82021-09-30 16:17:37 +02008986 task_wakeup(task, TASK_WOKEN_INIT);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008987
8988 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02008989
8990 alloc_error:
8991 task_destroy(task);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008992 hlua_unref(L, ref);
Aurelien DARRAGONb8038992023-03-09 16:48:30 +01008993 for (it = 0; it < nb_arg; it++) {
8994 hlua_unref(L, arg_ref[it]);
8995 }
Christopher Faulet5294ec02021-04-12 12:24:47 +02008996 hlua_ctx_destroy(hlua);
8997 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8998 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008999}
9000
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009001/* called from unsafe location */
9002static void hlua_event_subscription_destroy(struct hlua_event_sub *hlua_sub)
9003{
9004 /* hlua cleanup */
9005
9006 hlua_lock(hlua_sub->hlua);
9007 /* registry is shared between coroutines */
9008 hlua_unref(hlua_sub->hlua->T, hlua_sub->fcn_ref);
9009 hlua_unlock(hlua_sub->hlua);
9010
9011 hlua_ctx_destroy(hlua_sub->hlua);
9012
9013 /* free */
9014 pool_free(pool_head_hlua_event_sub, hlua_sub);
9015}
9016
9017/* single event handler: hlua ctx is shared between multiple events handlers
9018 * issued from the same subscription. Thus, it is not destroyed when the event
9019 * is processed: it is destroyed when no more events are expected for the
9020 * subscription (ie: when the subscription ends).
9021 *
9022 * Moreover, events are processed sequentially within the subscription:
9023 * one event must be fully processed before another one may be processed.
9024 * This ensures proper consistency for lua event handling from an ordering
9025 * point of view. This is especially useful with server events for example
9026 * where ADD/DEL/UP/DOWN events ordering really matters to trigger specific
9027 * actions from lua (e.g.: sending emails or making API calls).
9028 *
9029 * Due to this design, each lua event handler is pleased to process the event
9030 * as fast as possible to prevent the event queue from growing up.
9031 * Strictly speaking, there is no runtime limit for the callback function
9032 * (timeout set to default task timeout), but if the event queue goes past
9033 * the limit of unconsumed events an error will be reported and the
9034 * susbscription will pause itself for as long as it takes for the handler to
9035 * catch up (events will be lost as a result).
9036 * If the event handler does not need the sequential ordering and wants to
9037 * process multiple events at a time, it may spawn a new side-task using
9038 * 'core.register_task' to delegate the event handling and make parallel event
9039 * processing within the same subscription set.
9040 */
9041static void hlua_event_handler(struct hlua *hlua)
9042{
9043 enum hlua_exec status;
9044
9045 /* If it is the first call to the task, we must initialize the
9046 * execution timeouts.
9047 */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01009048 if (!HLUA_IS_RUNNING(hlua))
9049 hlua_timer_init(&hlua->timer, hlua_timeout_task);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009050
9051 /* make sure to reset the task expiry before each hlua_ctx_resume()
9052 * since the task is re-used for multiple cb function calls
9053 * We couldn't risk to have t->expire pointing to a past date because
9054 * it was set during last function invocation but was never reset since
9055 * (ie: E_AGAIN)
9056 */
9057 hlua->task->expire = TICK_ETERNITY;
9058
9059 /* Execute the Lua code. */
9060 status = hlua_ctx_resume(hlua, 1);
9061
9062 switch (status) {
9063 /* finished or yield */
9064 case HLUA_E_OK:
9065 break;
9066
9067 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
9068 notification_gc(&hlua->com);
9069 hlua->task->expire = hlua->wake_time;
9070 break;
9071
9072 /* finished with error. */
9073 case HLUA_E_ETMOUT:
9074 SEND_ERR(NULL, "Lua event_hdl: execution timeout.\n");
9075 break;
9076
9077 case HLUA_E_ERRMSG:
9078 SEND_ERR(NULL, "Lua event_hdl: %s.\n", lua_tostring(hlua->T, -1));
9079 break;
9080
9081 case HLUA_E_ERR:
9082 default:
9083 SEND_ERR(NULL, "Lua event_hdl: unknown error.\n");
9084 break;
9085 }
9086}
9087
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +02009088__LJMP static void hlua_event_hdl_cb_push_event_checkres(lua_State *L,
9089 struct event_hdl_cb_data_server_checkres *check)
9090{
9091 lua_pushstring(L, "agent");
9092 lua_pushboolean(L, check->agent);
9093 lua_settable(L, -3);
9094 lua_pushstring(L, "result");
9095 switch (check->result) {
9096 case CHK_RES_FAILED:
9097 lua_pushstring(L, "FAILED");
9098 break;
9099 case CHK_RES_PASSED:
9100 lua_pushstring(L, "PASSED");
9101 break;
9102 case CHK_RES_CONDPASS:
9103 lua_pushstring(L, "CONDPASS");
9104 break;
9105 default:
9106 lua_pushnil(L);
9107 break;
9108 }
9109 lua_settable(L, -3);
9110
9111 lua_pushstring(L, "duration");
9112 lua_pushinteger(L, check->duration);
9113 lua_settable(L, -3);
9114
9115 lua_pushstring(L, "reason");
9116 lua_newtable(L);
9117
9118 lua_pushstring(L, "short");
9119 lua_pushstring(L, get_check_status_info(check->reason.status));
9120 lua_settable(L, -3);
9121 lua_pushstring(L, "desc");
9122 lua_pushstring(L, get_check_status_description(check->reason.status));
9123 lua_settable(L, -3);
9124 if (check->reason.status >= HCHK_STATUS_L57DATA) {
9125 /* code only available when the check reached data analysis stage */
9126 lua_pushstring(L, "code");
9127 lua_pushinteger(L, check->reason.code);
9128 lua_settable(L, -3);
9129 }
9130
9131 lua_settable(L, -3); /* reason table */
9132
9133 lua_pushstring(L, "health");
9134 lua_newtable(L);
9135
9136 lua_pushstring(L, "cur");
9137 lua_pushinteger(L, check->health.cur);
9138 lua_settable(L, -3);
9139 lua_pushstring(L, "rise");
9140 lua_pushinteger(L, check->health.rise);
9141 lua_settable(L, -3);
9142 lua_pushstring(L, "fall");
9143 lua_pushinteger(L, check->health.fall);
9144 lua_settable(L, -3);
9145
9146 lua_settable(L, -3); /* health table */
9147}
9148
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009149/* This function pushes various arguments such as event type and event data to
9150 * the lua function that will be called to consume the event.
9151 */
9152__LJMP static void hlua_event_hdl_cb_push_args(struct hlua_event_sub *hlua_sub,
9153 struct event_hdl_async_event *e)
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009154{
9155 struct hlua *hlua = hlua_sub->hlua;
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009156 struct event_hdl_sub_type event = e->type;
9157 void *data = e->data;
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009158
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009159 /* push event type */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009160 hlua->nargs = 1;
9161 lua_pushstring(hlua->T, event_hdl_sub_type_to_string(event));
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009162
9163 /* push event data (according to event type) */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009164 if (event_hdl_sub_family_equal(EVENT_HDL_SUB_SERVER, event)) {
9165 struct event_hdl_cb_data_server *e_server = data;
9166 struct proxy *px;
9167 struct server *server;
9168
9169 hlua->nargs += 1;
9170 lua_newtable(hlua->T);
9171 /* Add server name */
9172 lua_pushstring(hlua->T, "name");
9173 lua_pushstring(hlua->T, e_server->safe.name);
9174 lua_settable(hlua->T, -3);
9175 /* Add server puid */
9176 lua_pushstring(hlua->T, "puid");
9177 lua_pushinteger(hlua->T, e_server->safe.puid);
9178 lua_settable(hlua->T, -3);
9179 /* Add server rid */
9180 lua_pushstring(hlua->T, "rid");
9181 lua_pushinteger(hlua->T, e_server->safe.rid);
9182 lua_settable(hlua->T, -3);
9183 /* Add server proxy name */
9184 lua_pushstring(hlua->T, "proxy_name");
9185 lua_pushstring(hlua->T, e_server->safe.proxy_name);
9186 lua_settable(hlua->T, -3);
Aurelien DARRAGON55f84c72023-03-22 17:49:04 +01009187 /* Add server proxy uuid */
9188 lua_pushstring(hlua->T, "proxy_uuid");
9189 lua_pushinteger(hlua->T, e_server->safe.proxy_uuid);
9190 lua_settable(hlua->T, -3);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009191
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +02009192 /* special events, fetch additional info with explicit type casting */
9193 if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_STATE, event)) {
9194 struct event_hdl_cb_data_server_state *state = data;
9195 int it;
9196
9197 if (!lua_checkstack(hlua->T, 20))
9198 WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
9199
9200 /* state subclass */
9201 lua_pushstring(hlua->T, "state");
9202 lua_newtable(hlua->T);
9203
9204 lua_pushstring(hlua->T, "admin");
9205 lua_pushboolean(hlua->T, state->safe.type);
9206 lua_settable(hlua->T, -3);
9207
9208 /* is it because of a check ? */
9209 if (!state->safe.type &&
9210 (state->safe.op_st_chg.cause == SRV_OP_STCHGC_HEALTH ||
9211 state->safe.op_st_chg.cause == SRV_OP_STCHGC_AGENT)) {
9212 /* yes, provide check result */
9213 lua_pushstring(hlua->T, "check");
9214 lua_newtable(hlua->T);
9215 hlua_event_hdl_cb_push_event_checkres(hlua->T, &state->safe.op_st_chg.check);
9216 lua_settable(hlua->T, -3); /* check table */
9217 }
9218
9219 lua_pushstring(hlua->T, "cause");
9220 if (state->safe.type)
9221 lua_pushstring(hlua->T, srv_adm_st_chg_cause(state->safe.adm_st_chg.cause));
9222 else
9223 lua_pushstring(hlua->T, srv_op_st_chg_cause(state->safe.op_st_chg.cause));
9224 lua_settable(hlua->T, -3);
9225
9226 /* old_state, new_state */
9227 for (it = 0; it < 2; it++) {
9228 enum srv_state srv_state = (!it) ? state->safe.old_state : state->safe.new_state;
9229
9230 lua_pushstring(hlua->T, (!it) ? "old_state" : "new_state");
9231 switch (srv_state) {
9232 case SRV_ST_STOPPED:
9233 lua_pushstring(hlua->T, "STOPPED");
9234 break;
9235 case SRV_ST_STOPPING:
9236 lua_pushstring(hlua->T, "STOPPING");
9237 break;
9238 case SRV_ST_STARTING:
9239 lua_pushstring(hlua->T, "STARTING");
9240 break;
9241 case SRV_ST_RUNNING:
9242 lua_pushstring(hlua->T, "RUNNING");
9243 break;
9244 default:
9245 lua_pushnil(hlua->T);
9246 break;
9247 }
9248 lua_settable(hlua->T, -3);
9249 }
9250
9251 /* requeued */
9252 lua_pushstring(hlua->T, "requeued");
9253 lua_pushinteger(hlua->T, state->safe.requeued);
9254 lua_settable(hlua->T, -3);
9255
9256 lua_settable(hlua->T, -3); /* state table */
9257 }
Aurelien DARRAGON948dd3d2023-04-26 11:27:09 +02009258 else if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_ADMIN, event)) {
9259 struct event_hdl_cb_data_server_admin *admin = data;
9260 int it;
9261
9262 if (!lua_checkstack(hlua->T, 20))
9263 WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
9264
9265 /* admin subclass */
9266 lua_pushstring(hlua->T, "admin");
9267 lua_newtable(hlua->T);
9268
9269 lua_pushstring(hlua->T, "cause");
9270 lua_pushstring(hlua->T, srv_adm_st_chg_cause(admin->safe.cause));
9271 lua_settable(hlua->T, -3);
9272
9273 /* old_admin, new_admin */
9274 for (it = 0; it < 2; it++) {
9275 enum srv_admin srv_admin = (!it) ? admin->safe.old_admin : admin->safe.new_admin;
9276
9277 lua_pushstring(hlua->T, (!it) ? "old_admin" : "new_admin");
9278
9279 /* admin state matrix */
9280 lua_newtable(hlua->T);
9281
9282 lua_pushstring(hlua->T, "MAINT");
9283 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_MAINT);
9284 lua_settable(hlua->T, -3);
9285 lua_pushstring(hlua->T, "FMAINT");
9286 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_FMAINT);
9287 lua_settable(hlua->T, -3);
9288 lua_pushstring(hlua->T, "IMAINT");
9289 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_IMAINT);
9290 lua_settable(hlua->T, -3);
9291 lua_pushstring(hlua->T, "RMAINT");
9292 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_RMAINT);
9293 lua_settable(hlua->T, -3);
9294 lua_pushstring(hlua->T, "CMAINT");
9295 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_CMAINT);
9296 lua_settable(hlua->T, -3);
9297
9298 lua_pushstring(hlua->T, "DRAIN");
9299 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_DRAIN);
9300 lua_settable(hlua->T, -3);
9301 lua_pushstring(hlua->T, "FDRAIN");
9302 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_FDRAIN);
9303 lua_settable(hlua->T, -3);
9304 lua_pushstring(hlua->T, "IDRAIN");
9305 lua_pushboolean(hlua->T, srv_admin & SRV_ADMF_IDRAIN);
9306 lua_settable(hlua->T, -3);
9307
9308 lua_settable(hlua->T, -3); /* matrix table */
9309 }
9310 /* requeued */
9311 lua_pushstring(hlua->T, "requeued");
9312 lua_pushinteger(hlua->T, admin->safe.requeued);
9313 lua_settable(hlua->T, -3);
9314
9315 lua_settable(hlua->T, -3); /* admin table */
9316 }
Aurelien DARRAGON0bd53b22023-03-30 15:53:33 +02009317 else if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_CHECK, event)) {
9318 struct event_hdl_cb_data_server_check *check = data;
9319
9320 if (!lua_checkstack(hlua->T, 20))
9321 WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error."));
9322
9323 /* check subclass */
9324 lua_pushstring(hlua->T, "check");
9325 lua_newtable(hlua->T);
9326
9327 /* check result snapshot */
9328 hlua_event_hdl_cb_push_event_checkres(hlua->T, &check->safe.res);
9329
9330 lua_settable(hlua->T, -3); /* check table */
9331 }
Aurelien DARRAGONc99f3ad2023-04-12 15:47:16 +02009332
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009333 /* attempt to provide reference server object
9334 * (if it wasn't removed yet, SERVER_DEL will never succeed here)
9335 */
Aurelien DARRAGON3d9bf4e2023-03-22 17:46:12 +01009336 px = proxy_find_by_id(e_server->safe.proxy_uuid, PR_CAP_BE, 0);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009337 BUG_ON(!px);
9338 server = findserver_unique_id(px, e_server->safe.puid, e_server->safe.rid);
9339 if (server) {
9340 lua_pushstring(hlua->T, "reference");
9341 hlua_fcn_new_server(hlua->T, server);
9342 lua_settable(hlua->T, -3);
9343 }
9344 }
9345 /* sub mgmt */
9346 hlua->nargs += 1;
9347 hlua_fcn_new_event_sub(hlua->T, hlua_sub->sub);
Aurelien DARRAGON096b3832023-04-20 11:32:46 +02009348
9349 /* when? */
9350 hlua->nargs += 1;
9351 lua_pushinteger(hlua->T, e->when.tv_sec);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009352}
9353
9354/* events runner: if there's an ongoing hlua event handling process, finish it
9355 * then, check if there are new events waiting to be processed
9356 * (events are processed sequentially)
9357 *
9358 * We have a safety measure to warn/guard if the event queue is growing up
9359 * too much due to many events being generated and lua handler is unable to
9360 * keep up the pace (e.g.: when the event queue grows past 100 unconsumed events).
9361 * TODO: make it tunable
9362 */
9363static struct task *hlua_event_runner(struct task *task, void *context, unsigned int state)
9364{
9365 struct hlua_event_sub *hlua_sub = context;
9366 struct event_hdl_async_event *event;
9367 const char *error = NULL;
9368
9369 if (!hlua_sub->paused && event_hdl_async_equeue_size(&hlua_sub->equeue) > 100) {
Aurelien DARRAGON7428ada2023-05-15 18:46:44 +02009370 const char *trace = NULL;
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009371
9372 /* We reached the limit of pending events in the queue: we should
9373 * warn the user, and temporarily pause the subscription to give a chance
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009374 * to the handler to catch up? (it also prevents resource shortage since
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009375 * the queue could grow indefinitely otherwise)
9376 * TODO: find a way to inform the handler that it missed some events
9377 * (example: stats within the subscription in event_hdl api exposed via lua api?)
9378 *
9379 * Nonetheless, reaching this limit means that the handler is not fast enough
9380 * and/or that it subscribed to events that happen too frequently and did not
9381 * expect it. This could come from an inadequate design in the user's script.
9382 */
9383 event_hdl_pause(hlua_sub->sub);
9384 hlua_sub->paused = 1;
9385
Aurelien DARRAGON7428ada2023-05-15 18:46:44 +02009386 if (SET_SAFE_LJMP(hlua_sub->hlua)) {
9387 /* The following Lua call may fail. */
9388 trace = hlua_traceback(hlua_sub->hlua->T, ", ");
9389 /* At this point the execution is safe. */
9390 RESET_SAFE_LJMP(hlua_sub->hlua);
9391 } else {
9392 /* Lua error was raised while fetching lua trace from current ctx */
9393 SEND_ERR(NULL, "Lua event_hdl: unexpected error (memory failure?).\n");
9394 }
9395 ha_warning("Lua event_hdl: pausing the subscription because the handler fails "
9396 "to keep up the pace (%u unconsumed events) from %s.\n",
9397 event_hdl_async_equeue_size(&hlua_sub->equeue),
9398 (trace) ? trace : "[unknown]");
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009399 }
9400
9401 if (HLUA_IS_RUNNING(hlua_sub->hlua)) {
9402 /* ongoing hlua event handler, resume it */
9403 hlua_event_handler(hlua_sub->hlua);
9404 } else if ((event = event_hdl_async_equeue_pop(&hlua_sub->equeue))) { /* check for new events */
9405 if (event_hdl_sub_type_equal(event->type, EVENT_HDL_SUB_END)) {
9406 /* ending event: no more events to come */
9407 event_hdl_async_free_event(event);
9408 task_destroy(task);
9409 hlua_event_subscription_destroy(hlua_sub);
9410 return NULL;
9411 }
9412 /* new event: start processing it */
9413
9414 /* The following Lua calls can fail. */
9415 if (!SET_SAFE_LJMP(hlua_sub->hlua)) {
9416 if (lua_type(hlua_sub->hlua->T, -1) == LUA_TSTRING)
9417 error = lua_tostring(hlua_sub->hlua->T, -1);
9418 else
9419 error = "critical error";
9420 ha_alert("Lua event_hdl: %s.\n", error);
9421 goto skip_event;
9422 }
9423
9424 /* Check stack available size. */
9425 if (!lua_checkstack(hlua_sub->hlua->T, 5)) {
9426 ha_alert("Lua event_hdl: full stack.\n");
9427 RESET_SAFE_LJMP(hlua_sub->hlua);
9428 goto skip_event;
9429 }
9430
9431 /* Restore the function in the stack. */
9432 hlua_pushref(hlua_sub->hlua->T, hlua_sub->fcn_ref);
9433
9434 /* push args */
9435 hlua_sub->hlua->nargs = 0;
Aurelien DARRAGON2f6a07d2023-03-27 18:16:21 +02009436 MAY_LJMP(hlua_event_hdl_cb_push_args(hlua_sub, event));
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009437
9438 /* At this point the execution is safe. */
9439 RESET_SAFE_LJMP(hlua_sub->hlua);
9440
9441 /* At this point the event was successfully translated into hlua ctx,
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009442 * or hlua error occurred, so we can safely discard it
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009443 */
9444 event_hdl_async_free_event(event);
9445 event = NULL;
9446
9447 hlua_event_handler(hlua_sub->hlua);
9448 skip_event:
9449 if (event)
9450 event_hdl_async_free_event(event);
9451
9452 }
9453
9454 if (!HLUA_IS_RUNNING(hlua_sub->hlua)) {
9455 /* we just finished the processing of one event..
9456 * check for new events before becoming idle
9457 */
9458 if (!event_hdl_async_equeue_isempty(&hlua_sub->equeue)) {
9459 /* more events to process, make sure the task
9460 * will be resumed ASAP to process pending events
9461 */
9462 task_wakeup(task, TASK_WOKEN_OTHER);
9463 }
9464 else if (hlua_sub->paused) {
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009465 /* empty queue, the handler caught up: resume the subscription */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009466 event_hdl_resume(hlua_sub->sub);
9467 hlua_sub->paused = 0;
9468 }
9469 }
9470
9471 return task;
9472}
9473
9474/* Must be called directly under lua protected/safe environment
9475 * (not from external callback)
9476 * <fcn_ref> should NOT be dropped after the function successfully returns:
9477 * it will be done automatically in hlua_event_subscription_destroy() when the
9478 * subscription ends.
9479 *
9480 * Returns the new subscription on success and NULL on failure (memory error)
9481 */
9482static struct event_hdl_sub *hlua_event_subscribe(event_hdl_sub_list *list, struct event_hdl_sub_type e_type,
9483 int state_id, int fcn_ref)
9484{
9485 struct hlua_event_sub *hlua_sub;
9486 struct task *task = NULL;
9487
9488 hlua_sub = pool_alloc(pool_head_hlua_event_sub);
9489 if (!hlua_sub)
9490 goto mem_error;
9491 hlua_sub->task = NULL;
9492 hlua_sub->hlua = NULL;
9493 hlua_sub->paused = 0;
9494 if ((task = task_new_here()) == NULL) {
9495 ha_alert("out of memory while allocating hlua event task");
9496 goto mem_error;
9497 }
9498 task->process = hlua_event_runner;
9499 task->context = hlua_sub;
9500 event_hdl_async_equeue_init(&hlua_sub->equeue);
9501 hlua_sub->task = task;
9502 hlua_sub->fcn_ref = fcn_ref;
9503 hlua_sub->state_id = state_id;
9504 hlua_sub->hlua = pool_alloc(pool_head_hlua);
9505 if (!hlua_sub->hlua)
9506 goto mem_error;
9507 HLUA_INIT(hlua_sub->hlua);
9508 if (!hlua_ctx_init(hlua_sub->hlua, hlua_sub->state_id, task))
9509 goto mem_error;
9510
9511 hlua_sub->sub = event_hdl_subscribe_ptr(list, e_type,
9512 EVENT_HDL_ASYNC_TASK(&hlua_sub->equeue,
9513 task,
9514 hlua_sub,
9515 NULL));
9516 if (!hlua_sub->sub)
9517 goto mem_error;
9518
9519 return hlua_sub->sub; /* returns pointer to event_hdl_sub struct */
9520
9521 mem_error:
9522 if (hlua_sub) {
Tim Duesterhusfe83f582023-04-22 17:47:34 +02009523 task_destroy(hlua_sub->task);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009524 if (hlua_sub->hlua)
9525 hlua_ctx_destroy(hlua_sub->hlua);
9526 pool_free(pool_head_hlua_event_sub, hlua_sub);
9527 }
9528
9529 return NULL;
9530}
9531
9532/* looks for an array of strings referring to a composition of event_hdl subscription
9533 * types at <index> in <L> stack
9534 */
9535__LJMP static struct event_hdl_sub_type hlua_check_event_sub_types(lua_State *L, int index)
9536{
9537 struct event_hdl_sub_type subscriptions;
9538 const char *msg;
9539
9540 if (lua_type(L, index) != LUA_TTABLE) {
9541 msg = lua_pushfstring(L, "table of strings expected, got %s", luaL_typename(L, index));
9542 luaL_argerror(L, index, msg);
9543 }
9544
9545 subscriptions = EVENT_HDL_SUB_NONE;
9546
9547 /* browse the argument as an array. */
9548 lua_pushnil(L);
9549 while (lua_next(L, index) != 0) {
9550 if (lua_type(L, -1) != LUA_TSTRING) {
9551 msg = lua_pushfstring(L, "table of strings expected, got %s", luaL_typename(L, index));
9552 luaL_argerror(L, index, msg);
9553 }
9554
9555 if (event_hdl_sub_type_equal(EVENT_HDL_SUB_NONE, event_hdl_string_to_sub_type(lua_tostring(L, -1)))) {
9556 msg = lua_pushfstring(L, "'%s' event type is unknown", lua_tostring(L, -1));
9557 luaL_argerror(L, index, msg);
9558 }
9559
9560 /* perform subscriptions |= current sub */
9561 subscriptions = event_hdl_sub_type_add(subscriptions, event_hdl_string_to_sub_type(lua_tostring(L, -1)));
9562
9563 /* pop the current value. */
9564 lua_pop(L, 1);
9565 }
9566
9567 return subscriptions;
9568}
9569
9570/* Wrapper for hlua_fcn_new_event_sub(): catch errors raised by
9571 * the function to prevent LJMP
9572 *
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009573 * If no error occurred, the function returns 1, else it returns 0 and
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009574 * the error message is pushed at the top of the stack
9575 */
9576__LJMP static int _hlua_new_event_sub_safe(lua_State *L)
9577{
9578 struct event_hdl_sub *sub = lua_touserdata(L, 1);
9579
9580 /* this function may raise errors */
9581 return MAY_LJMP(hlua_fcn_new_event_sub(L, sub));
9582}
9583static int hlua_new_event_sub_safe(lua_State *L, struct event_hdl_sub *sub)
9584{
9585 if (!lua_checkstack(L, 2))
9586 return 0;
9587 lua_pushcfunction(L, _hlua_new_event_sub_safe);
9588 lua_pushlightuserdata(L, sub);
9589 switch (lua_pcall(L, 1, 1, 0)) {
9590 case LUA_OK:
9591 return 1;
9592 default:
Ilya Shipitsinccf80122023-04-22 20:20:39 +02009593 /* error was caught */
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +01009594 return 0;
9595 }
9596}
9597
9598/* This function is a LUA helper used for registering lua event callbacks.
9599 * It expects an event subscription array and the function to be executed
9600 * when subscribed events occur (stack arguments).
9601 * It can be called from the "init" section, "post init" or during the runtime.
9602 *
9603 * <sub_list> is the subscription list where the subscription will be attempted
9604 *
9605 * Pushes the newly allocated subscription on the stack on success
9606 */
9607__LJMP int hlua_event_sub(lua_State *L, event_hdl_sub_list *sub_list)
9608{
9609 struct hlua *hlua;
9610 struct event_hdl_sub *sub;
9611 struct event_hdl_sub_type subscriptions;
9612 int fcn_ref;
9613 int state_id;
9614
9615 MAY_LJMP(check_args(L, 2, "event_sub"));
9616
9617 /* Get the reference state */
9618 hlua = hlua_gethlua(L);
9619 if (hlua)
9620 /* we are in runtime processing, any thread may subscribe to events:
9621 * subscription events will be handled by the thread who performed
9622 * the registration.
9623 */
9624 state_id = hlua->state_id;
9625 else {
9626 /* we are in initialization mode, only thread 0 (actual calling thread)
9627 * may subscribe to events to prevent the same handler (from different lua
9628 * stacks) from being registered multiple times
9629 *
9630 * hlua_state_id == 0: monostack (lua-load)
9631 * hlua_state_id > 0: hlua_state_id=tid+1, multi-stack (lua-load-per-thread)
9632 * (thus if hlua_state_id > 1, it means we are not in primary thread ctx)
9633 */
9634 if (hlua_state_id > 1)
9635 return 0; /* skip registration */
9636 state_id = hlua_state_id;
9637 }
9638
9639 /* First argument : event subscriptions. */
9640 subscriptions = MAY_LJMP(hlua_check_event_sub_types(L, 1));
9641
9642 if (event_hdl_sub_type_equal(subscriptions, EVENT_HDL_SUB_NONE)) {
9643 WILL_LJMP(luaL_error(L, "event_sub: no valid event types were provided"));
9644 return 0; /* Never reached */
9645 }
9646
9647 /* Second argument : lua function. */
9648 fcn_ref = MAY_LJMP(hlua_checkfunction(L, 2));
9649
9650 /* try to subscribe */
9651 sub = hlua_event_subscribe(sub_list, subscriptions, state_id, fcn_ref);
9652 if (!sub) {
9653 hlua_unref(L, fcn_ref);
9654 WILL_LJMP(luaL_error(L, "event_sub: lua out of memory error"));
9655 return 0; /* Never reached */
9656 }
9657
9658 /* push the subscription to the stack
9659 *
9660 * Here we use the safe function so that lua errors will be
9661 * handled explicitly to prevent 'sub' from being lost
9662 */
9663 if (!hlua_new_event_sub_safe(L, sub)) {
9664 /* Some events could already be pending in the handler's queue.
9665 * However it is wiser to cancel the subscription since we are unable to
9666 * provide a valid reference to it.
9667 * Pending events will be delivered (unless lua keeps raising errors).
9668 */
9669 event_hdl_unsubscribe(sub); /* cancel the subscription */
9670 WILL_LJMP(luaL_error(L, "event_sub: cannot push the subscription (%s)", lua_tostring(L, -1)));
9671 return 0; /* Never reached */
9672 }
9673 event_hdl_drop(sub); /* sub has been duplicated, discard old ref */
9674
9675 return 1;
9676}
9677
9678/* This function is a LUA wrapper used for registering global lua event callbacks
9679 * The new subscription is pushed onto the stack on success
9680 * Returns the number of arguments pushed to the stack (1 for success)
9681 */
9682__LJMP static int hlua_event_global_sub(lua_State *L)
9683{
9684 /* NULL <sub_list> = global subscription list */
9685 return MAY_LJMP(hlua_event_sub(L, NULL));
9686}
9687
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009688/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
9689 * doesn't allow "yield" functions because the HAProxy engine cannot
9690 * resume converters.
9691 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02009692static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009693{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009694 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02009695 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009696 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009697
Willy Tarreaube508f12016-03-10 11:47:01 +01009698 if (!stream)
9699 return 0;
9700
Willy Tarreau87b09662015-04-03 00:22:06 +02009701 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009702 * Lua context can be not initialized. This behavior
9703 * permits to save performances because a systematic
9704 * Lua initialization cause 5% performances loss.
9705 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009706 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009707 struct hlua *hlua;
9708
9709 hlua = pool_alloc(pool_head_hlua);
9710 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009711 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
9712 return 0;
9713 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009714 HLUA_INIT(hlua);
9715 stream->hlua = hlua;
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01009716 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009717 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
9718 return 0;
9719 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009720 }
9721
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009722 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009723 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009724
9725 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009726 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009727 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
9728 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009729 else
9730 error = "critical error";
9731 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009732 return 0;
9733 }
9734
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009735 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009736 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009737 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009738 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009739 return 0;
9740 }
9741
9742 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009743 hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009744
9745 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009746 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009747 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009748 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009749 return 0;
9750 }
Aurelien DARRAGON41217722023-05-17 10:44:47 +02009751 MAY_LJMP(hlua_smp2lua(stream->hlua->T, smp));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009752 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009753
9754 /* push keywords in the stack. */
9755 if (arg_p) {
9756 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009757 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009758 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009759 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009760 return 0;
9761 }
Aurelien DARRAGONe5c048a2023-05-17 10:51:50 +02009762 MAY_LJMP(hlua_arg2lua(stream->hlua->T, arg_p));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009763 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009764 }
9765 }
9766
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009767 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01009768 hlua_timer_init(&stream->hlua->timer, hlua_timeout_session);
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009769
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009770 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009771 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009772 }
9773
9774 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009775 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009776 /* finished. */
9777 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02009778 /* If the stack is empty, the function fails. */
9779 if (lua_gettop(stream->hlua->T) <= 0)
9780 return 0;
9781
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009782 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009783 hlua_lua2smp(stream->hlua->T, -1, smp);
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02009784 /* dup the smp before popping the related lua value and
9785 * returning it to haproxy
9786 */
9787 smp_dup(smp);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009788 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009789 return 1;
9790
9791 /* yield. */
9792 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009793 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009794 return 0;
9795
9796 /* finished with error. */
9797 case HLUA_E_ERRMSG:
9798 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009799 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009800 fcn->name, lua_tostring(stream->hlua->T, -1));
9801 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009802 return 0;
9803
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009804 case HLUA_E_ETMOUT:
9805 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
9806 return 0;
9807
9808 case HLUA_E_NOMEM:
9809 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
9810 return 0;
9811
9812 case HLUA_E_YIELD:
9813 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
9814 return 0;
9815
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009816 case HLUA_E_ERR:
9817 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009818 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01009819 __fallthrough;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009820
9821 default:
9822 return 0;
9823 }
9824}
9825
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009826/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
9827 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01009828 * resume sample-fetches. This function will be called by the sample
9829 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009830 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02009831static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
9832 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009833{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009834 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02009835 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009836 const char *error;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02009837 unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009838
Willy Tarreaube508f12016-03-10 11:47:01 +01009839 if (!stream)
9840 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01009841
Willy Tarreau87b09662015-04-03 00:22:06 +02009842 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009843 * Lua context can be not initialized. This behavior
9844 * permits to save performances because a systematic
9845 * Lua initialization cause 5% performances loss.
9846 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009847 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009848 struct hlua *hlua;
9849
9850 hlua = pool_alloc(pool_head_hlua);
9851 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009852 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
9853 return 0;
9854 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009855 hlua->T = NULL;
9856 stream->hlua = hlua;
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +01009857 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009858 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
9859 return 0;
9860 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009861 }
9862
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009863 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009864 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009865
9866 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009867 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009868 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
9869 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009870 else
9871 error = "critical error";
9872 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009873 return 0;
9874 }
9875
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009876 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009877 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009878 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009879 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009880 return 0;
9881 }
9882
9883 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009884 hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009885
9886 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02009887 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009888 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009889 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009890 return 0;
9891 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009892 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009893
9894 /* push keywords in the stack. */
9895 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
9896 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009897 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009898 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009899 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009900 return 0;
9901 }
Aurelien DARRAGONe5c048a2023-05-17 10:51:50 +02009902 MAY_LJMP(hlua_arg2lua(stream->hlua->T, arg_p));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009903 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009904 }
9905
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009906 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +01009907 hlua_timer_init(&stream->hlua->timer, hlua_timeout_session);
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009908
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009909 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009910 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009911 }
9912
9913 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009914 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009915 /* finished. */
9916 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02009917 /* If the stack is empty, the function fails. */
9918 if (lua_gettop(stream->hlua->T) <= 0)
9919 return 0;
9920
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009921 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009922 hlua_lua2smp(stream->hlua->T, -1, smp);
Aurelien DARRAGON1c07da42023-05-17 16:06:11 +02009923 /* dup the smp before popping the related lua value and
9924 * returning it to haproxy
9925 */
9926 smp_dup(smp);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009927 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009928
9929 /* Set the end of execution flag. */
9930 smp->flags &= ~SMP_F_MAY_CHANGE;
9931 return 1;
9932
9933 /* yield. */
9934 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009935 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009936 return 0;
9937
9938 /* finished with error. */
9939 case HLUA_E_ERRMSG:
9940 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009941 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009942 fcn->name, lua_tostring(stream->hlua->T, -1));
9943 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009944 return 0;
9945
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009946 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009947 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
9948 return 0;
9949
9950 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009951 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
9952 return 0;
9953
9954 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009955 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
9956 return 0;
9957
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009958 case HLUA_E_ERR:
9959 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009960 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01009961 __fallthrough;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009962
9963 default:
9964 return 0;
9965 }
9966}
9967
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009968/* This function is an LUA binding used for registering
9969 * "sample-conv" functions. It expects a converter name used
9970 * in the haproxy configuration file, and an LUA function.
9971 */
9972__LJMP static int hlua_register_converters(lua_State *L)
9973{
9974 struct sample_conv_kw_list *sck;
9975 const char *name;
9976 int ref;
9977 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02009978 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009979 struct sample_conv *sc;
9980 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009981
9982 MAY_LJMP(check_args(L, 2, "register_converters"));
9983
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01009984 if (hlua_gethlua(L)) {
9985 /* runtime processing */
9986 WILL_LJMP(luaL_error(L, "register_converters: not available outside of body context"));
9987 }
9988
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009989 /* First argument : converter name. */
9990 name = MAY_LJMP(luaL_checkstring(L, 1));
9991
9992 /* Second argument : lua function. */
9993 ref = MAY_LJMP(hlua_checkfunction(L, 2));
9994
Thierry Fournierf67442e2020-11-28 20:41:07 +01009995 /* Check if the converter is already registered */
9996 trash = get_trash_chunk();
9997 chunk_printf(trash, "lua.%s", name);
9998 sc = find_sample_conv(trash->area, trash->data);
9999 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010000 fcn = sc->private;
10001 if (fcn->function_ref[hlua_state_id] != -1) {
10002 ha_warning("Trying to register converter 'lua.%s' more than once. "
10003 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010004 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010005 }
10006 fcn->function_ref[hlua_state_id] = ref;
10007 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010008 }
10009
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010010 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010011 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010012 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +020010013 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010014 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010015 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +020010016 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010017
10018 /* Fill fcn. */
10019 fcn->name = strdup(name);
10020 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +020010021 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010022 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010023
10024 /* List head */
10025 sck->list.n = sck->list.p = NULL;
10026
10027 /* converter keyword. */
10028 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010029 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010030 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +020010031 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010032
10033 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
10034 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +010010035 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 +010010036 sck->kw[0].val_args = NULL;
10037 sck->kw[0].in_type = SMP_T_STR;
10038 sck->kw[0].out_type = SMP_T_STR;
10039 sck->kw[0].private = fcn;
10040
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010041 /* Register this new converter */
10042 sample_register_convs(sck);
10043
10044 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +020010045
10046 alloc_error:
10047 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010048 hlua_unref(L, ref);
Christopher Fauletaa224302021-04-12 14:08:21 +020010049 ha_free(&sck);
10050 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10051 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +010010052}
10053
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010054/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010055 * "sample-fetch" functions. It expects a converter name used
10056 * in the haproxy configuration file, and an LUA function.
10057 */
10058__LJMP static int hlua_register_fetches(lua_State *L)
10059{
10060 const char *name;
10061 int ref;
10062 int len;
10063 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +020010064 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010065 struct sample_fetch *sf;
10066 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010067
10068 MAY_LJMP(check_args(L, 2, "register_fetches"));
10069
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010010070 if (hlua_gethlua(L)) {
10071 /* runtime processing */
10072 WILL_LJMP(luaL_error(L, "register_fetches: not available outside of body context"));
10073 }
10074
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010075 /* First argument : sample-fetch name. */
10076 name = MAY_LJMP(luaL_checkstring(L, 1));
10077
10078 /* Second argument : lua function. */
10079 ref = MAY_LJMP(hlua_checkfunction(L, 2));
10080
Thierry Fournierf67442e2020-11-28 20:41:07 +010010081 /* Check if the sample-fetch is already registered */
10082 trash = get_trash_chunk();
10083 chunk_printf(trash, "lua.%s", name);
10084 sf = find_sample_fetch(trash->area, trash->data);
10085 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010086 fcn = sf->private;
10087 if (fcn->function_ref[hlua_state_id] != -1) {
10088 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
10089 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010090 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010091 }
10092 fcn->function_ref[hlua_state_id] = ref;
10093 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010094 }
10095
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010096 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010097 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010098 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +020010099 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010100 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010101 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +020010102 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010103
10104 /* Fill fcn. */
10105 fcn->name = strdup(name);
10106 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +020010107 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010108 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010109
10110 /* List head */
10111 sfk->list.n = sfk->list.p = NULL;
10112
10113 /* sample-fetch keyword. */
10114 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010115 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010116 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +020010117 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010118
10119 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
10120 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +010010121 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 +010010122 sfk->kw[0].val_args = NULL;
10123 sfk->kw[0].out_type = SMP_T_STR;
10124 sfk->kw[0].use = SMP_USE_HTTP_ANY;
10125 sfk->kw[0].val = 0;
10126 sfk->kw[0].private = fcn;
10127
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010128 /* Register this new fetch. */
10129 sample_register_fetches(sfk);
10130
10131 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +020010132
10133 alloc_error:
10134 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010135 hlua_unref(L, ref);
Christopher Faulet2567f182021-04-12 14:11:50 +020010136 ha_free(&sfk);
10137 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10138 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +010010139}
10140
Christopher Faulet501465d2020-02-26 14:54:16 +010010141/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010142 */
Christopher Faulet501465d2020-02-26 14:54:16 +010010143__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010144{
Thierry Fournier4234dbd2020-11-28 13:18:23 +010010145 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010146 unsigned int delay;
Aurelien DARRAGON2a9764b2023-04-04 18:41:04 +020010147 int wakeup_ms; // tick value
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010148
Thierry Fournier4234dbd2020-11-28 13:18:23 +010010149 /* Get hlua struct, or NULL if we execute from main lua state */
10150 hlua = hlua_gethlua(L);
10151 if (!hlua) {
10152 return 0;
10153 }
10154
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010155 MAY_LJMP(check_args(L, 1, "wake_time"));
10156
10157 delay = MAY_LJMP(luaL_checkinteger(L, 1));
10158 wakeup_ms = tick_add(now_ms, delay);
10159 hlua->wake_time = wakeup_ms;
10160 return 0;
10161}
10162
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010163/* This function is a wrapper to execute each LUA function declared as an action
10164 * wrapper during the initialisation period. This function may return any
10165 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
10166 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
10167 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010168 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010169static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +020010170 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010171{
10172 char **arg;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +020010173 unsigned int hflags = HLUA_TXN_ACT_CTX;
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010174 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +010010175 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010176
10177 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +010010178 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
10179 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
10180 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
10181 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010182 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010183 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010184 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010185 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010186
Willy Tarreau87b09662015-04-03 00:22:06 +020010187 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +010010188 * Lua context can be not initialized. This behavior
10189 * permits to save performances because a systematic
10190 * Lua initialization cause 5% performances loss.
10191 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010192 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +010010193 struct hlua *hlua;
10194
10195 hlua = pool_alloc(pool_head_hlua);
10196 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010197 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010198 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010199 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010200 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +010010201 HLUA_INIT(hlua);
10202 s->hlua = hlua;
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010010203 if (!hlua_ctx_init(s->hlua, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn), s->task)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010204 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010205 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010206 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010207 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +010010208 }
10209
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010210 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010211 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010212
10213 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010214 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010215 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
10216 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +010010217 else
10218 error = "critical error";
10219 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010220 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010221 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010222 }
10223
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010224 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010225 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010226 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010227 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010228 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010229 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010230 }
10231
10232 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010233 hlua_pushref(s->hlua->T, rule->arg.hlua_rule->fcn->function_ref[s->hlua->state_id]);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010234
Willy Tarreau87b09662015-04-03 00:22:06 +020010235 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +020010236 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010237 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010238 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010239 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010240 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010241 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010242 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010243
10244 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010245 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010246 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010247 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010248 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010249 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010250 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010251 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010252 lua_pushstring(s->hlua->T, *arg);
10253 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010254 }
10255
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010256 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010257 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010258
Thierry FOURNIERbd413492015-03-03 16:52:26 +010010259 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010010260 hlua_timer_init(&s->hlua->timer, hlua_timeout_session);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010261 }
10262
10263 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +010010264 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010265 /* finished. */
10266 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010267 /* Catch the return value */
10268 if (lua_gettop(s->hlua->T) > 0)
10269 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010270
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010271 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +020010272 if (act_ret == ACT_RET_YIELD) {
10273 if (flags & ACT_OPT_FINAL)
10274 goto err_yield;
10275
Christopher Faulet8f587ea2020-07-28 12:01:55 +020010276 if (dir == SMP_OPT_DIR_REQ)
10277 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
10278 s->hlua->wake_time);
10279 else
10280 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
10281 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010010282 }
10283 goto end;
10284
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010285 /* yield. */
10286 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +010010287 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +020010288 if (dir == SMP_OPT_DIR_REQ)
10289 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
10290 s->hlua->wake_time);
10291 else
10292 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
10293 s->hlua->wake_time);
10294
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010295 /* Some actions can be wake up when a "write" event
10296 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010297 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010298 */
Christopher Faulet51fa3582019-07-26 14:54:52 +020010299 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010010300 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010301 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010010302 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010303 act_ret = ACT_RET_YIELD;
10304 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010305
10306 /* finished with error. */
10307 case HLUA_E_ERRMSG:
10308 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010309 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010310 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +010010311 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010312 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010313
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010314 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +010010315 SEND_ERR(px, "Lua function '%s': execution timeout.\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_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +010010319 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010320 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010321
10322 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +020010323 err_yield:
10324 act_ret = ACT_RET_CONT;
Aurelien DARRAGONcf5b75e2023-08-31 21:45:21 +020010325 SEND_ERR(px, "Lua function '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010326 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010327 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010328
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010329 case HLUA_E_ERR:
10330 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +020010331 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010332 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010333
10334 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010335 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010336 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010337
10338 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +020010339 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +020010340 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +010010341 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010342}
10343
Willy Tarreau144f84a2021-03-02 16:09:26 +010010344struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010345{
Olivier Houchard9f6af332018-05-25 14:04:04 +020010346 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010347
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010348 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +020010349 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +020010350 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010351}
10352
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010353static int hlua_applet_tcp_init(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010354{
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010355 struct hlua_tcp_ctx *tcp_ctx = applet_reserve_svcctx(ctx, sizeof(*tcp_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +020010356 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010357 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010358 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010359 struct task *task;
10360 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +010010361 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010362
Willy Tarreaubafbe012017-11-24 17:34:44 +010010363 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010364 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010365 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010366 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010367 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010368 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010369 HLUA_INIT(hlua);
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010370 tcp_ctx->hlua = hlua;
10371 tcp_ctx->flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010372
10373 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +020010374 task = task_new_here();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010375 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010376 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010377 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010378 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010379 }
10380 task->nice = 0;
10381 task->context = ctx;
10382 task->process = hlua_applet_wakeup;
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010383 tcp_ctx->task = task;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010384
10385 /* In the execution wrappers linked with a stream, the
10386 * Lua context can be not initialized. This behavior
10387 * permits to save performances because a systematic
10388 * Lua initialization cause 5% performances loss.
10389 */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010010390 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010391 SEND_ERR(strm->be, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010392 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010393 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010394 }
10395
10396 /* Set timeout according with the applet configuration. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010010397 hlua_timer_init(&hlua->timer, ctx->applet->timeout);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010398
10399 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010400 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +010010401 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10402 error = lua_tostring(hlua->T, -1);
10403 else
10404 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010405 SEND_ERR(strm->be, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010406 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +020010407 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010408 }
10409
10410 /* Check stack available size. */
10411 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010412 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010413 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010414 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010415 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010416 }
10417
10418 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010419 hlua_pushref(hlua->T, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010420
10421 /* Create and and push object stream in the stack. */
10422 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010423 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010424 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010425 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010426 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010427 }
10428 hlua->nargs = 1;
10429
10430 /* push keywords in the stack. */
10431 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
10432 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010433 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010434 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010435 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010436 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010437 }
10438 lua_pushstring(hlua->T, *arg);
10439 hlua->nargs++;
10440 }
10441
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010442 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010443
10444 /* Wakeup the applet ASAP. */
Willy Tarreau90e8b452022-05-25 18:21:43 +020010445 applet_need_more_data(ctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +020010446 applet_have_more_data(ctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010447
Christopher Fauletc9929382022-05-12 11:52:27 +020010448 return 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010449}
10450
Willy Tarreau60409db2019-08-21 14:14:50 +020010451void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010452{
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010453 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010454 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010455 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010456 struct act_rule *rule = ctx->rule;
10457 struct proxy *px = strm->be;
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010458 struct hlua *hlua = tcp_ctx->hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010459
Christopher Faulet31572222023-03-31 11:13:48 +020010460 if (unlikely(se_fl_test(ctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
10461 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010462
Christopher Faulet31572222023-03-31 11:13:48 +020010463 /* The applet execution is already done. */
10464 if (tcp_ctx->flags & APPLET_DONE)
10465 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010466
10467 /* Execute the function. */
10468 switch (hlua_ctx_resume(hlua, 1)) {
10469 /* finished. */
10470 case HLUA_E_OK:
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010471 tcp_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +020010472 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
10473 break;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010474
10475 /* yield. */
10476 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +010010477 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010478 task_schedule(tcp_ctx->task, hlua->wake_time);
Christopher Faulet31572222023-03-31 11:13:48 +020010479 break;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010480
10481 /* finished with error. */
10482 case HLUA_E_ERRMSG:
10483 /* Display log. */
10484 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010485 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010486 lua_pop(hlua->T, 1);
10487 goto error;
10488
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010489 case HLUA_E_ETMOUT:
10490 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010491 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010492 goto error;
10493
10494 case HLUA_E_NOMEM:
10495 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010496 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010497 goto error;
10498
10499 case HLUA_E_YIELD: /* unexpected */
10500 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010501 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010502 goto error;
10503
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010504 case HLUA_E_ERR:
10505 /* Display log. */
10506 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010507 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010508 goto error;
10509
10510 default:
10511 goto error;
10512 }
10513
Christopher Faulet31572222023-03-31 11:13:48 +020010514out:
10515 /* eat the whole request */
10516 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
10517 return;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010518
Christopher Faulet31572222023-03-31 11:13:48 +020010519error:
10520 se_fl_set(ctx->sedesc, SE_FL_ERROR);
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010521 tcp_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +020010522 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010523}
10524
10525static void hlua_applet_tcp_release(struct appctx *ctx)
10526{
Willy Tarreaue23f33b2022-05-06 14:07:13 +020010527 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
10528
10529 task_destroy(tcp_ctx->task);
10530 tcp_ctx->task = NULL;
10531 hlua_ctx_destroy(tcp_ctx->hlua);
10532 tcp_ctx->hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010533}
10534
Christopher Fauletc9929382022-05-12 11:52:27 +020010535/* The function returns 0 if the initialisation is complete or -1 if
10536 * an errors occurs. It also reserves the appctx for an hlua_http_ctx.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010537 */
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010538static int hlua_applet_http_init(struct appctx *ctx)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010539{
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010540 struct hlua_http_ctx *http_ctx = applet_reserve_svcctx(ctx, sizeof(*http_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +020010541 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010542 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010543 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010544 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010545 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010546 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +010010547 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010548
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010549 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +010010550 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010551 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010552 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010553 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010554 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010555 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010556 HLUA_INIT(hlua);
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010557 http_ctx->hlua = hlua;
10558 http_ctx->left_bytes = -1;
10559 http_ctx->flags = 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010560
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +010010561 if (txn->req.flags & HTTP_MSGF_VER_11)
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010562 http_ctx->flags |= APPLET_HTTP11;
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +010010563
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010564 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +020010565 task = task_new_here();
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010566 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010567 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010568 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010569 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010570 }
10571 task->nice = 0;
10572 task->context = ctx;
10573 task->process = hlua_applet_wakeup;
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010574 http_ctx->task = task;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010575
10576 /* In the execution wrappers linked with a stream, the
10577 * Lua context can be not initialized. This behavior
10578 * permits to save performances because a systematic
10579 * Lua initialization cause 5% performances loss.
10580 */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010010581 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010582 SEND_ERR(strm->be, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010583 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +020010584 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010585 }
10586
10587 /* Set timeout according with the applet configuration. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010010588 hlua_timer_init(&hlua->timer, ctx->applet->timeout);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010589
10590 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010591 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +010010592 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10593 error = lua_tostring(hlua->T, -1);
10594 else
10595 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010596 SEND_ERR(strm->be, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010597 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +020010598 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010599 }
10600
10601 /* Check stack available size. */
10602 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010603 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010604 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010605 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010606 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010607 }
10608
10609 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010610 hlua_pushref(hlua->T, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010611
10612 /* Create and and push object stream in the stack. */
10613 if (!hlua_applet_http_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010614 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010615 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010616 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010617 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010618 }
10619 hlua->nargs = 1;
10620
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010621 /* push keywords in the stack. */
10622 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
10623 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +010010624 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +010010625 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010626 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +020010627 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010628 }
10629 lua_pushstring(hlua->T, *arg);
10630 hlua->nargs++;
10631 }
10632
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010633 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010634
10635 /* Wakeup the applet when data is ready for read. */
Willy Tarreau90e8b452022-05-25 18:21:43 +020010636 applet_need_more_data(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010637
Christopher Fauletc9929382022-05-12 11:52:27 +020010638 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010639}
10640
Willy Tarreau60409db2019-08-21 14:14:50 +020010641void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010642{
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010643 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010644 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +020010645 struct stream *strm = __sc_strm(sc);
10646 struct channel *req = sc_oc(sc);
10647 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010648 struct act_rule *rule = ctx->rule;
10649 struct proxy *px = strm->be;
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010650 struct hlua *hlua = http_ctx->hlua;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010651 struct htx *req_htx, *res_htx;
10652
10653 res_htx = htx_from_buf(&res->buf);
10654
Christopher Faulet31572222023-03-31 11:13:48 +020010655 if (unlikely(se_fl_test(ctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
10656 goto out;
10657
10658 /* The applet execution is already done. */
10659 if (http_ctx->flags & APPLET_DONE)
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010660 goto out;
10661
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010662 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010663 if (!b_size(&res->buf)) {
Christopher Faulet7b3d38a2023-05-05 11:28:45 +020010664 sc_need_room(sc, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010665 goto out;
10666 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010667
10668 /* Set the currently running flag. */
10669 if (!HLUA_IS_RUNNING(hlua) &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010670 !(http_ctx->flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +020010671 if (!co_data(req)) {
Willy Tarreau90e8b452022-05-25 18:21:43 +020010672 applet_need_more_data(ctx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010673 goto out;
10674 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010675 }
10676
Christopher Faulet31572222023-03-31 11:13:48 +020010677 /* Execute the function. */
10678 switch (hlua_ctx_resume(hlua, 1)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010679 /* finished. */
10680 case HLUA_E_OK:
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010681 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010682 break;
10683
10684 /* yield. */
10685 case HLUA_E_AGAIN:
10686 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010687 task_schedule(http_ctx->task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +010010688 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010689
10690 /* finished with error. */
10691 case HLUA_E_ERRMSG:
10692 /* Display log. */
10693 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010694 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010695 lua_pop(hlua->T, 1);
10696 goto error;
10697
10698 case HLUA_E_ETMOUT:
10699 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010700 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010701 goto error;
10702
10703 case HLUA_E_NOMEM:
10704 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010705 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010706 goto error;
10707
10708 case HLUA_E_YIELD: /* unexpected */
10709 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010710 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010711 goto error;
10712
10713 case HLUA_E_ERR:
10714 /* Display log. */
10715 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Christopher Faulet31572222023-03-31 11:13:48 +020010716 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010717 goto error;
10718
10719 default:
10720 goto error;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010721 }
10722
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010723 if (http_ctx->flags & APPLET_DONE) {
10724 if (http_ctx->flags & APPLET_RSP_SENT)
Christopher Faulet31572222023-03-31 11:13:48 +020010725 goto out;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +010010726
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010727 if (!(http_ctx->flags & APPLET_HDR_SENT))
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010728 goto error;
10729
Christopher Fauletf89af9c2022-04-07 10:07:18 +020010730 /* no more data are expected. If the response buffer is empty
10731 * for a chunked message, be sure to add something (EOT block in
10732 * this case) to have something to send. It is important to be
10733 * sure the EOM flags will be handled by the endpoint.
10734 */
10735 if (htx_is_empty(res_htx) && (strm->txn->rsp.flags & (HTTP_MSGF_XFER_LEN|HTTP_MSGF_CNT_LEN)) == HTTP_MSGF_XFER_LEN) {
10736 if (!htx_add_endof(res_htx, HTX_BLK_EOT)) {
Christopher Faulet7b3d38a2023-05-05 11:28:45 +020010737 sc_need_room(sc, sizeof(struct htx_blk)+1);
Christopher Fauletf89af9c2022-04-07 10:07:18 +020010738 goto out;
10739 }
10740 channel_add_input(res, 1);
10741 }
10742
Christopher Fauletd1ac2b92020-12-02 19:12:22 +010010743 res_htx->flags |= HTX_FL_EOM;
Christopher Faulet31572222023-03-31 11:13:48 +020010744 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010745 strm->txn->status = http_ctx->status;
10746 http_ctx->flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010747 }
10748
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010749 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010750 htx_to_buf(res_htx, &res->buf);
Christopher Faulet31572222023-03-31 11:13:48 +020010751 /* eat the whole request */
10752 if (co_data(req)) {
10753 req_htx = htx_from_buf(&req->buf);
10754 co_htx_skip(req, req_htx, co_data(req));
10755 htx_to_buf(req_htx, &req->buf);
10756 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010757 return;
10758
10759 error:
10760
10761 /* If we are in HTTP mode, and we are not send any
10762 * data, return a 500 server error in best effort:
10763 * if there is no room available in the buffer,
10764 * just close the connection.
10765 */
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010766 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +020010767 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010768
10769 channel_erase(res);
10770 res->buf.data = b_data(err);
10771 memcpy(res->buf.area, b_head(err), b_data(err));
10772 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +010010773 channel_add_input(res, res_htx->data);
Christopher Faulet31572222023-03-31 11:13:48 +020010774 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010775 }
Christopher Faulet31572222023-03-31 11:13:48 +020010776 else
10777 se_fl_set(ctx->sedesc, SE_FL_ERROR);
10778
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010779 if (!(strm->flags & SF_ERR_MASK))
10780 strm->flags |= SF_ERR_RESOURCE;
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010781 http_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +020010782 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +010010783}
10784
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010785static void hlua_applet_http_release(struct appctx *ctx)
10786{
Willy Tarreauaa229cc2022-05-06 14:26:10 +020010787 struct hlua_http_ctx *http_ctx = ctx->svcctx;
10788
10789 task_destroy(http_ctx->task);
10790 http_ctx->task = NULL;
10791 hlua_ctx_destroy(http_ctx->hlua);
10792 http_ctx->hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010793}
10794
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010795/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010796 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020010797 *
10798 * This function can fail with an abort() due to an Lua critical error.
10799 * We are in the configuration parsing process of HAProxy, this abort() is
10800 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010801 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010802static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
10803 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010804{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010805 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010806 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010807
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010808 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010809 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010810 if (!rule->arg.hlua_rule) {
10811 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +020010812 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010813 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010814
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010815 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +020010816 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
10817 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010818 if (!rule->arg.hlua_rule->args) {
10819 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +020010820 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010821 }
10822
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010823 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010824 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010825
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010826 /* Expect some arguments */
10827 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +010010828 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010829 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +020010830 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010831 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +010010832 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010833 if (!rule->arg.hlua_rule->args[i]) {
10834 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +020010835 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010836 }
10837 (*cur_arg)++;
10838 }
10839 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010840
Thierry FOURNIER42148732015-09-02 17:17:33 +020010841 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +020010842 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +020010843 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +020010844
10845 error:
10846 if (rule->arg.hlua_rule) {
10847 if (rule->arg.hlua_rule->args) {
10848 for (i = 0; i < fcn->nargs; i++)
10849 ha_free(&rule->arg.hlua_rule->args[i]);
10850 ha_free(&rule->arg.hlua_rule->args);
10851 }
10852 ha_free(&rule->arg.hlua_rule);
10853 }
10854 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +010010855}
10856
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010857static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
10858 struct act_rule *rule, char **err)
10859{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010860 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010861
Thierry FOURNIER718e2a72015-12-20 20:13:14 +010010862 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010863 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +010010864 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050010865 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +010010866 * the call of this analyzer.
10867 */
10868 if (rule->from != ACT_F_HTTP_REQ) {
10869 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
10870 return ACT_RET_PRS_ERR;
10871 }
10872
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010873 /* Memory for the rule. */
10874 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
10875 if (!rule->arg.hlua_rule) {
10876 memprintf(err, "out of memory error");
10877 return ACT_RET_PRS_ERR;
10878 }
10879
10880 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010881 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010882
10883 /* TODO: later accept arguments. */
10884 rule->arg.hlua_rule->args = NULL;
10885
10886 /* Add applet pointer in the rule. */
10887 rule->applet.obj_type = OBJ_TYPE_APPLET;
10888 rule->applet.name = fcn->name;
10889 rule->applet.init = hlua_applet_http_init;
10890 rule->applet.fct = hlua_applet_http_fct;
10891 rule->applet.release = hlua_applet_http_release;
10892 rule->applet.timeout = hlua_timeout_applet;
10893
10894 return ACT_RET_PRS_OK;
10895}
10896
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010897/* This function is an LUA binding used for registering
10898 * "sample-conv" functions. It expects a converter name used
10899 * in the haproxy configuration file, and an LUA function.
10900 */
10901__LJMP static int hlua_register_action(lua_State *L)
10902{
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010903 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010904 const char *name;
10905 int ref;
10906 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010907 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010908 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010909 struct buffer *trash;
10910 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010911
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010912 /* Initialise the number of expected arguments at 0. */
10913 nargs = 0;
10914
10915 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
10916 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010917
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010010918 if (hlua_gethlua(L)) {
10919 /* runtime processing */
10920 WILL_LJMP(luaL_error(L, "register_action: not available outside of body context"));
10921 }
10922
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010923 /* First argument : converter name. */
10924 name = MAY_LJMP(luaL_checkstring(L, 1));
10925
10926 /* Second argument : environment. */
10927 if (lua_type(L, 2) != LUA_TTABLE)
10928 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
10929
10930 /* Third argument : lua function. */
10931 ref = MAY_LJMP(hlua_checkfunction(L, 3));
10932
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010933 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010934 if (lua_gettop(L) >= 4)
10935 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
10936
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010937 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010938 lua_pushnil(L);
10939 while (lua_next(L, 2) != 0) {
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010940 if (lua_type(L, -1) != LUA_TSTRING) {
10941 hlua_unref(L, ref);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010942 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010943 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010944
Thierry Fournierf67442e2020-11-28 20:41:07 +010010945 /* Check if action exists */
10946 trash = get_trash_chunk();
10947 chunk_printf(trash, "lua.%s", name);
10948 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
10949 akw = tcp_req_cont_action(trash->area);
10950 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
10951 akw = tcp_res_cont_action(trash->area);
10952 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
10953 akw = action_http_req_custom(trash->area);
10954 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
10955 akw = action_http_res_custom(trash->area);
10956 } else {
10957 akw = NULL;
10958 }
10959 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010960 fcn = akw->private;
10961 if (fcn->function_ref[hlua_state_id] != -1) {
10962 ha_warning("Trying to register action 'lua.%s' more than once. "
10963 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010964 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010965 }
10966 fcn->function_ref[hlua_state_id] = ref;
10967
10968 /* pop the environment string. */
10969 lua_pop(L, 1);
10970 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010971 }
10972
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010973 /* Check required environment. Only accepted "http" or "tcp". */
10974 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010975 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010976 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010977 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010978 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010979 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010980 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010981
10982 /* Fill fcn. */
10983 fcn->name = strdup(name);
10984 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010985 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010986 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010987
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -070010988 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010989 fcn->nargs = nargs;
10990
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010991 /* List head */
10992 akl->list.n = akl->list.p = NULL;
10993
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010994 /* action keyword. */
10995 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010996 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010997 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010998 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010999
11000 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
11001
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020011002 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011003 akl->kw[0].private = fcn;
11004 akl->kw[0].parse = action_register_lua;
11005
11006 /* select the action registering point. */
11007 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
11008 tcp_req_cont_keywords_register(akl);
11009 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
11010 tcp_res_cont_keywords_register(akl);
11011 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
11012 http_req_keywords_register(akl);
11013 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
11014 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011015 else {
11016 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011017 hlua_unref(L, ref);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011018 if (akl)
11019 ha_free((char **)&(akl->kw[0].kw));
11020 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010011021 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011022 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
11023 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011024 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011025
11026 /* pop the environment string. */
11027 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011028
11029 /* reset for next loop */
11030 akl = NULL;
11031 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011032 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011033 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011034
11035 alloc_error:
11036 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011037 hlua_unref(L, ref);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020011038 ha_free(&akl);
11039 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11040 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011041}
11042
11043static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
11044 struct act_rule *rule, char **err)
11045{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020011046 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011047
Christopher Faulet280f85b2019-07-15 15:02:04 +020011048 if (px->mode == PR_MODE_HTTP) {
11049 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +010011050 return ACT_RET_PRS_ERR;
11051 }
11052
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011053 /* Memory for the rule. */
11054 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
11055 if (!rule->arg.hlua_rule) {
11056 memprintf(err, "out of memory error");
11057 return ACT_RET_PRS_ERR;
11058 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011059
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011060 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010011061 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011062
11063 /* TODO: later accept arguments. */
11064 rule->arg.hlua_rule->args = NULL;
11065
11066 /* Add applet pointer in the rule. */
11067 rule->applet.obj_type = OBJ_TYPE_APPLET;
11068 rule->applet.name = fcn->name;
11069 rule->applet.init = hlua_applet_tcp_init;
11070 rule->applet.fct = hlua_applet_tcp_fct;
11071 rule->applet.release = hlua_applet_tcp_release;
11072 rule->applet.timeout = hlua_timeout_applet;
11073
11074 return 0;
11075}
11076
11077/* This function is an LUA binding used for registering
11078 * "sample-conv" functions. It expects a converter name used
11079 * in the haproxy configuration file, and an LUA function.
11080 */
11081__LJMP static int hlua_register_service(lua_State *L)
11082{
11083 struct action_kw_list *akl;
11084 const char *name;
11085 const char *env;
11086 int ref;
11087 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +020011088 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011089 struct buffer *trash;
11090 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011091
11092 MAY_LJMP(check_args(L, 3, "register_service"));
11093
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010011094 if (hlua_gethlua(L)) {
11095 /* runtime processing */
11096 WILL_LJMP(luaL_error(L, "register_service: not available outside of body context"));
11097 }
11098
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011099 /* First argument : converter name. */
11100 name = MAY_LJMP(luaL_checkstring(L, 1));
11101
11102 /* Second argument : environment. */
11103 env = MAY_LJMP(luaL_checkstring(L, 2));
11104
11105 /* Third argument : lua function. */
11106 ref = MAY_LJMP(hlua_checkfunction(L, 3));
11107
Thierry Fournierf67442e2020-11-28 20:41:07 +010011108 /* Check for service already registered */
11109 trash = get_trash_chunk();
11110 chunk_printf(trash, "lua.%s", name);
11111 akw = service_find(trash->area);
11112 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010011113 fcn = akw->private;
11114 if (fcn->function_ref[hlua_state_id] != -1) {
11115 ha_warning("Trying to register service 'lua.%s' more than once. "
11116 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011117 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011118 }
11119 fcn->function_ref[hlua_state_id] = ref;
11120 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011121 }
11122
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011123 /* Allocate and fill the sample fetch keyword struct. */
11124 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
11125 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011126 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010011127 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011128 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011129 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011130
11131 /* Fill fcn. */
11132 len = strlen("<lua.>") + strlen(name) + 1;
11133 fcn->name = calloc(1, len);
11134 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011135 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011136 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +010011137 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011138
11139 /* List head */
11140 akl->list.n = akl->list.p = NULL;
11141
11142 /* converter keyword. */
11143 len = strlen("lua.") + strlen(name) + 1;
11144 akl->kw[0].kw = calloc(1, len);
11145 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +020011146 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011147
11148 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
11149
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +010011150 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011151 if (strcmp(env, "tcp") == 0)
11152 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020011153 else if (strcmp(env, "http") == 0)
11154 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +020011155 else {
11156 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011157 hlua_unref(L, ref);
Christopher Faulet5c028d72021-04-12 15:11:44 +020011158 if (akl)
11159 ha_free((char **)&(akl->kw[0].kw));
11160 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010011161 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +010011162 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +020011163 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011164
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020011165 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011166 akl->kw[0].private = fcn;
11167
11168 /* End of array. */
11169 memset(&akl->kw[1], 0, sizeof(*akl->kw));
11170
11171 /* Register this new converter */
11172 service_keywords_register(akl);
11173
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011174 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +020011175
11176 alloc_error:
11177 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011178 hlua_unref(L, ref);
Christopher Faulet5c028d72021-04-12 15:11:44 +020011179 ha_free(&akl);
11180 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11181 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020011182}
11183
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011184/* This function initialises Lua cli handler. It copies the
11185 * arguments in the Lua stack and create channel IO objects.
11186 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +020011187static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011188{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011189 struct hlua_cli_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011190 struct hlua *hlua;
11191 struct hlua_function *fcn;
11192 int i;
11193 const char *error;
11194
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011195 fcn = private;
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011196 ctx->fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010011197
Willy Tarreaubafbe012017-11-24 17:34:44 +010011198 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010011199 if (!hlua) {
11200 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010011201 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010011202 }
11203 HLUA_INIT(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011204 ctx->hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011205
11206 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +050011207 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011208 * applet_http. It is absolutely compatible.
11209 */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011210 ctx->task = task_new_here();
11211 if (!ctx->task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +010011212 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010011213 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011214 }
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011215 ctx->task->nice = 0;
11216 ctx->task->context = appctx;
11217 ctx->task->process = hlua_applet_wakeup;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011218
11219 /* Initialises the Lua context */
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010011220 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), ctx->task)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011221 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010011222 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011223 }
11224
11225 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010011226 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011227 if (lua_type(hlua->T, -1) == LUA_TSTRING)
11228 error = lua_tostring(hlua->T, -1);
11229 else
11230 error = "critical error";
11231 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
11232 goto error;
11233 }
11234
11235 /* Check stack available size. */
11236 if (!lua_checkstack(hlua->T, 2)) {
11237 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
11238 goto error;
11239 }
11240
11241 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011242 hlua_pushref(hlua->T, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011243
11244 /* Once the arguments parsed, the CLI is like an AppletTCP,
11245 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011246 */
11247 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
11248 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
11249 goto error;
11250 }
11251 hlua->nargs = 1;
11252
11253 /* push keywords in the stack. */
11254 for (i = 0; *args[i]; i++) {
11255 /* Check stack available size. */
11256 if (!lua_checkstack(hlua->T, 1)) {
11257 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
11258 goto error;
11259 }
11260 lua_pushstring(hlua->T, args[i]);
11261 hlua->nargs++;
11262 }
11263
11264 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010011265 hlua_timer_init(&hlua->timer, hlua_timeout_session);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011266
11267 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010011268 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011269
11270 /* It's ok */
11271 return 0;
11272
11273 /* It's not ok. */
11274error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +010011275 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011276 hlua_ctx_destroy(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011277 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011278 return 1;
11279}
11280
11281static int hlua_cli_io_handler_fct(struct appctx *appctx)
11282{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011283 struct hlua_cli_ctx *ctx = appctx->svcctx;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011284 struct hlua *hlua;
Willy Tarreau475e4632022-05-27 10:26:46 +020011285 struct stconn *sc;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011286 struct hlua_function *fcn;
11287
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011288 hlua = ctx->hlua;
Willy Tarreauc12b3212022-05-27 11:08:15 +020011289 sc = appctx_sc(appctx);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011290 fcn = ctx->fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011291
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011292 /* Execute the function. */
11293 switch (hlua_ctx_resume(hlua, 1)) {
11294
11295 /* finished. */
11296 case HLUA_E_OK:
11297 return 1;
11298
11299 /* yield. */
11300 case HLUA_E_AGAIN:
11301 /* We want write. */
11302 if (HLUA_IS_WAKERESWR(hlua))
Christopher Faulet7b3d38a2023-05-05 11:28:45 +020011303 sc_need_room(sc, -1);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011304 /* Set the timeout. */
11305 if (hlua->wake_time != TICK_ETERNITY)
11306 task_schedule(hlua->task, hlua->wake_time);
11307 return 0;
11308
11309 /* finished with error. */
11310 case HLUA_E_ERRMSG:
11311 /* Display log. */
11312 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
11313 fcn->name, lua_tostring(hlua->T, -1));
11314 lua_pop(hlua->T, 1);
11315 return 1;
11316
Thierry Fournierd5b073c2018-05-21 19:42:47 +020011317 case HLUA_E_ETMOUT:
11318 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
11319 fcn->name);
11320 return 1;
11321
11322 case HLUA_E_NOMEM:
11323 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
11324 fcn->name);
11325 return 1;
11326
11327 case HLUA_E_YIELD: /* unexpected */
11328 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
11329 fcn->name);
11330 return 1;
11331
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011332 case HLUA_E_ERR:
11333 /* Display log. */
11334 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
11335 fcn->name);
11336 return 1;
11337
11338 default:
11339 return 1;
11340 }
11341
11342 return 1;
11343}
11344
11345static void hlua_cli_io_release_fct(struct appctx *appctx)
11346{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020011347 struct hlua_cli_ctx *ctx = appctx->svcctx;
11348
11349 hlua_ctx_destroy(ctx->hlua);
11350 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011351}
11352
11353/* This function is an LUA binding used for registering
11354 * new keywords in the cli. It expects a list of keywords
11355 * which are the "path". It is limited to 5 keywords. A
11356 * description of the command, a function to be executed
11357 * for the parsing and a function for io handlers.
11358 */
11359__LJMP static int hlua_register_cli(lua_State *L)
11360{
11361 struct cli_kw_list *cli_kws;
11362 const char *message;
11363 int ref_io;
11364 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011365 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011366 int index;
11367 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011368 struct buffer *trash;
11369 const char *kw[5];
11370 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011371 const char *errmsg;
Willy Tarreau22450af2023-04-07 15:27:55 +020011372 char *end;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011373
11374 MAY_LJMP(check_args(L, 3, "register_cli"));
11375
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010011376 if (hlua_gethlua(L)) {
11377 /* runtime processing */
11378 WILL_LJMP(luaL_error(L, "register_cli: not available outside of body context"));
11379 }
11380
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011381 /* First argument : an array of maximum 5 keywords. */
11382 if (!lua_istable(L, 1))
11383 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
11384
11385 /* Second argument : string with contextual message. */
11386 message = MAY_LJMP(luaL_checkstring(L, 2));
11387
11388 /* Third and fourth argument : lua function. */
11389 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
11390
Thierry Fournierf67442e2020-11-28 20:41:07 +010011391 /* Check for CLI service already registered */
11392 trash = get_trash_chunk();
11393 index = 0;
11394 lua_pushnil(L);
11395 memset(kw, 0, sizeof(kw));
11396 while (lua_next(L, 1) != 0) {
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011397 if (index >= CLI_PREFIX_KW_NB) {
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 with a maximum of 5 entries"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011400 }
11401 if (lua_type(L, -1) != LUA_TSTRING) {
11402 hlua_unref(L, ref_io);
Thierry Fournierf67442e2020-11-28 20:41:07 +010011403 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011404 }
Thierry Fournierf67442e2020-11-28 20:41:07 +010011405 kw[index] = lua_tostring(L, -1);
11406 if (index == 0)
11407 chunk_printf(trash, "%s", kw[index]);
11408 else
11409 chunk_appendf(trash, " %s", kw[index]);
11410 index++;
11411 lua_pop(L, 1);
11412 }
11413 cli_kw = cli_find_kw_exact((char **)kw);
11414 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010011415 fcn = cli_kw->private;
11416 if (fcn->function_ref[hlua_state_id] != -1) {
11417 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
11418 "This will become a hard error in version 2.5.\n", trash->area);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011419 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011420 }
11421 fcn->function_ref[hlua_state_id] = ref_io;
11422 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010011423 }
11424
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011425 /* Allocate and fill the sample fetch keyword struct. */
11426 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011427 if (!cli_kws) {
11428 errmsg = "Lua out of memory error.";
11429 goto error;
11430 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +010011431 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011432 if (!fcn) {
11433 errmsg = "Lua out of memory error.";
11434 goto error;
11435 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011436
11437 /* Fill path. */
11438 index = 0;
11439 lua_pushnil(L);
11440 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011441 if (index >= 5) {
11442 errmsg = "1st argument must be a table with a maximum of 5 entries";
11443 goto error;
11444 }
11445 if (lua_type(L, -1) != LUA_TSTRING) {
11446 errmsg = "1st argument must be a table filled with strings";
11447 goto error;
11448 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011449 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011450 if (!cli_kws->kw[0].str_kw[index]) {
11451 errmsg = "Lua out of memory error.";
11452 goto error;
11453 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011454 index++;
11455 lua_pop(L, 1);
11456 }
11457
11458 /* Copy help message. */
11459 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011460 if (!cli_kws->kw[0].usage) {
11461 errmsg = "Lua out of memory error.";
11462 goto error;
11463 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011464
11465 /* Fill fcn io handler. */
11466 len = strlen("<lua.cli>") + 1;
11467 for (i = 0; i < index; i++)
11468 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
11469 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011470 if (!fcn->name) {
11471 errmsg = "Lua out of memory error.";
11472 goto error;
11473 }
Willy Tarreau22450af2023-04-07 15:27:55 +020011474
11475 end = fcn->name;
11476 len = 8;
11477 memcpy(end, "<lua.cli", len);
11478 end += len;
11479
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011480 for (i = 0; i < index; i++) {
Willy Tarreau22450af2023-04-07 15:27:55 +020011481 *(end++) = '.';
11482 len = strlen(cli_kws->kw[0].str_kw[i]);
11483 memcpy(end, cli_kws->kw[0].str_kw[i], len);
11484 end += len;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011485 }
Willy Tarreau22450af2023-04-07 15:27:55 +020011486 *(end++) = '>';
11487 *(end++) = 0;
11488
Thierry Fournierc7492592020-11-28 23:57:24 +010011489 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011490
11491 /* Fill last entries. */
11492 cli_kws->kw[0].private = fcn;
11493 cli_kws->kw[0].parse = hlua_cli_parse_fct;
11494 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
11495 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
11496
11497 /* Register this new converter */
11498 cli_register_kw(cli_kws);
11499
11500 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011501
11502 error:
11503 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011504 hlua_unref(L, ref_io);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020011505 if (cli_kws) {
11506 for (i = 0; i < index; i++)
11507 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
11508 ha_free((char **)&(cli_kws->kw[0].usage));
11509 }
11510 ha_free(&cli_kws);
11511 WILL_LJMP(luaL_error(L, errmsg));
11512 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010011513}
11514
Christopher Faulet69c581a2021-05-31 08:54:04 +020011515static int hlua_filter_init_per_thread(struct proxy *px, struct flt_conf *fconf)
11516{
11517 struct hlua_flt_config *conf = fconf->conf;
11518 lua_State *L;
11519 int error, pos, state_id, flt_ref;
11520
11521 state_id = reg_flt_to_stack_id(conf->reg);
11522 L = hlua_states[state_id];
11523 pos = lua_gettop(L);
11524
11525 /* The filter parsing function */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011526 hlua_pushref(L, conf->reg->fun_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011527
11528 /* Push the filter class on the stack and resolve all callbacks */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011529 hlua_pushref(L, conf->reg->flt_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011530
11531 /* Duplicate the filter class so each filter will have its own copy */
11532 lua_newtable(L);
11533 lua_pushnil(L);
11534
11535 while (lua_next(L, pos+2)) {
11536 lua_pushvalue(L, -2);
11537 lua_insert(L, -2);
11538 lua_settable(L, -4);
11539 }
Aurelien DARRAGON73d1a982023-03-20 17:42:08 +010011540 flt_ref = hlua_ref(L);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011541
11542 /* Remove the original lua filter class from the stack */
11543 lua_pop(L, 1);
11544
11545 /* Push the copy on the stack */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011546 hlua_pushref(L, flt_ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011547
11548 /* extra args are pushed in a table */
11549 lua_newtable(L);
11550 for (pos = 0; conf->args[pos]; pos++) {
11551 /* Check stack available size. */
11552 if (!lua_checkstack(L, 1)) {
11553 ha_alert("Lua filter '%s' : Lua error : full stack.", conf->reg->name);
11554 goto error;
11555 }
11556 lua_pushstring(L, conf->args[pos]);
11557 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
11558 }
11559
11560 error = lua_pcall(L, 2, LUA_MULTRET, 0);
11561 switch (error) {
11562 case LUA_OK:
11563 /* replace the filter ref */
11564 conf->ref[state_id] = flt_ref;
11565 break;
11566 case LUA_ERRRUN:
11567 ha_alert("Lua filter '%s' : runtime error : %s", conf->reg->name, lua_tostring(L, -1));
11568 goto error;
11569 case LUA_ERRMEM:
11570 ha_alert("Lua filter '%s' : out of memory error", conf->reg->name);
11571 goto error;
11572 case LUA_ERRERR:
11573 ha_alert("Lua filter '%s' : message handler error : %s", conf->reg->name, lua_tostring(L, -1));
11574 goto error;
11575#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
11576 case LUA_ERRGCMM:
11577 ha_alert("Lua filter '%s' : garbage collector error : %s", conf->reg->name, lua_tostring(L, -1));
11578 goto error;
11579#endif
11580 default:
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050011581 ha_alert("Lua filter '%s' : unknown error : %s", conf->reg->name, lua_tostring(L, -1));
Christopher Faulet69c581a2021-05-31 08:54:04 +020011582 goto error;
11583 }
11584
11585 lua_settop(L, 0);
11586 return 0;
11587
11588 error:
11589 lua_settop(L, 0);
11590 return -1;
11591}
11592
11593static void hlua_filter_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
11594{
11595 struct hlua_flt_config *conf = fconf->conf;
11596 lua_State *L;
11597 int state_id;
11598
11599 if (!conf)
11600 return;
11601
11602 state_id = reg_flt_to_stack_id(conf->reg);
11603 L = hlua_states[state_id];
Aurelien DARRAGONfde199d2023-03-20 15:09:33 +010011604 hlua_unref(L, conf->ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011605}
11606
11607static int hlua_filter_init(struct proxy *px, struct flt_conf *fconf)
11608{
11609 struct hlua_flt_config *conf = fconf->conf;
11610 int state_id = reg_flt_to_stack_id(conf->reg);
11611
11612 /* Rely on per-thread init for global scripts */
11613 if (!state_id)
11614 return hlua_filter_init_per_thread(px, fconf);
11615 return 0;
11616}
11617
11618static void hlua_filter_deinit(struct proxy *px, struct flt_conf *fconf)
11619{
11620
11621 if (fconf->conf) {
11622 struct hlua_flt_config *conf = fconf->conf;
11623 int state_id = reg_flt_to_stack_id(conf->reg);
11624 int pos;
11625
11626 /* Rely on per-thread deinit for global scripts */
11627 if (!state_id)
11628 hlua_filter_deinit_per_thread(px, fconf);
11629
11630 for (pos = 0; conf->args[pos]; pos++)
11631 free(conf->args[pos]);
11632 free(conf->args);
11633 }
11634 ha_free(&fconf->conf);
11635 ha_free((char **)&fconf->id);
11636 ha_free(&fconf->ops);
11637}
11638
11639static int hlua_filter_new(struct stream *s, struct filter *filter)
11640{
11641 struct hlua_flt_config *conf = FLT_CONF(filter);
11642 struct hlua_flt_ctx *flt_ctx = NULL;
11643 int ret = 1;
11644
11645 /* In the execution wrappers linked with a stream, the
11646 * Lua context can be not initialized. This behavior
11647 * permits to save performances because a systematic
11648 * Lua initialization cause 5% performances loss.
11649 */
11650 if (!s->hlua) {
11651 struct hlua *hlua;
11652
11653 hlua = pool_alloc(pool_head_hlua);
11654 if (!hlua) {
11655 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
11656 conf->reg->name);
11657 ret = 0;
11658 goto end;
11659 }
11660 HLUA_INIT(hlua);
11661 s->hlua = hlua;
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010011662 if (!hlua_ctx_init(s->hlua, reg_flt_to_stack_id(conf->reg), s->task)) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020011663 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
11664 conf->reg->name);
11665 ret = 0;
11666 goto end;
11667 }
11668 }
11669
11670 flt_ctx = pool_zalloc(pool_head_hlua_flt_ctx);
11671 if (!flt_ctx) {
11672 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11673 conf->reg->name);
11674 ret = 0;
11675 goto end;
11676 }
11677 flt_ctx->hlua[0] = pool_alloc(pool_head_hlua);
11678 flt_ctx->hlua[1] = pool_alloc(pool_head_hlua);
11679 if (!flt_ctx->hlua[0] || !flt_ctx->hlua[1]) {
11680 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11681 conf->reg->name);
11682 ret = 0;
11683 goto end;
11684 }
11685 HLUA_INIT(flt_ctx->hlua[0]);
11686 HLUA_INIT(flt_ctx->hlua[1]);
Aurelien DARRAGON6b0b9bd2023-03-21 14:02:16 +010011687 if (!hlua_ctx_init(flt_ctx->hlua[0], reg_flt_to_stack_id(conf->reg), s->task) ||
11688 !hlua_ctx_init(flt_ctx->hlua[1], reg_flt_to_stack_id(conf->reg), s->task)) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020011689 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
11690 conf->reg->name);
11691 ret = 0;
11692 goto end;
11693 }
11694
11695 if (!HLUA_IS_RUNNING(s->hlua)) {
11696 /* The following Lua calls can fail. */
11697 if (!SET_SAFE_LJMP(s->hlua)) {
11698 const char *error;
11699
11700 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
11701 error = lua_tostring(s->hlua->T, -1);
11702 else
11703 error = "critical error";
11704 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
11705 ret = 0;
11706 goto end;
11707 }
11708
11709 /* Check stack size. */
11710 if (!lua_checkstack(s->hlua->T, 1)) {
11711 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
Tim Duesterhus22817382021-09-11 23:17:25 +020011712 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011713 ret = 0;
11714 goto end;
11715 }
11716
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011717 hlua_pushref(s->hlua->T, conf->ref[s->hlua->state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011718 if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) {
11719 SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
11720 conf->reg->name);
11721 RESET_SAFE_LJMP(s->hlua);
11722 ret = 0;
11723 goto end;
11724 }
11725 lua_insert(s->hlua->T, -2);
11726
11727 /* Push the copy on the stack */
11728 s->hlua->nargs = 1;
11729
11730 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010011731 hlua_timer_init(&s->hlua->timer, hlua_timeout_session);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011732
11733 /* At this point the execution is safe. */
11734 RESET_SAFE_LJMP(s->hlua);
11735 }
11736
11737 switch (hlua_ctx_resume(s->hlua, 0)) {
11738 case HLUA_E_OK:
11739 /* Nothing returned or not a table, ignore the filter for current stream */
11740 if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) {
11741 ret = 0;
11742 goto end;
11743 }
11744
11745 /* Attached the filter pointer to the ctx */
11746 lua_pushstring(s->hlua->T, "__filter");
11747 lua_pushlightuserdata(s->hlua->T, filter);
11748 lua_settable(s->hlua->T, -3);
11749
11750 /* Save a ref on the filter ctx */
11751 lua_pushvalue(s->hlua->T, 1);
Aurelien DARRAGON73d1a982023-03-20 17:42:08 +010011752 flt_ctx->ref = hlua_ref(s->hlua->T);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011753 filter->ctx = flt_ctx;
11754 break;
11755 case HLUA_E_ERRMSG:
11756 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(s->hlua->T, -1));
11757 ret = -1;
11758 goto end;
11759 case HLUA_E_ETMOUT:
11760 SEND_ERR(s->be, "Lua filter '%s' : 'new' execution timeout.\n", conf->reg->name);
11761 ret = 0;
11762 goto end;
11763 case HLUA_E_NOMEM:
11764 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
11765 ret = 0;
11766 goto end;
11767 case HLUA_E_AGAIN:
11768 case HLUA_E_YIELD:
11769 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
11770 " are not allowed from 'new' function.\n", conf->reg->name);
11771 ret = 0;
11772 goto end;
11773 case HLUA_E_ERR:
11774 SEND_ERR(s->be, "Lua filter '%s': 'new' returns an unknown error.\n", conf->reg->name);
11775 ret = 0;
11776 goto end;
11777 default:
11778 ret = 0;
11779 goto end;
11780 }
11781
11782 end:
11783 if (s->hlua)
11784 lua_settop(s->hlua->T, 0);
11785 if (ret <= 0) {
11786 if (flt_ctx) {
11787 hlua_ctx_destroy(flt_ctx->hlua[0]);
11788 hlua_ctx_destroy(flt_ctx->hlua[1]);
11789 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
11790 }
11791 }
11792 return ret;
11793}
11794
11795static void hlua_filter_delete(struct stream *s, struct filter *filter)
11796{
11797 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11798
Aurelien DARRAGONfde199d2023-03-20 15:09:33 +010011799 hlua_unref(s->hlua->T, flt_ctx->ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011800 hlua_ctx_destroy(flt_ctx->hlua[0]);
11801 hlua_ctx_destroy(flt_ctx->hlua[1]);
11802 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
11803 filter->ctx = NULL;
11804}
11805
Christopher Faulet9f55a502020-02-25 15:21:02 +010011806static int hlua_filter_from_payload(struct filter *filter)
11807{
11808 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11809
11810 return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD));
11811}
11812
Christopher Fauletc404f112020-02-26 15:03:09 +010011813static int hlua_filter_callback(struct stream *s, struct filter *filter, const char *fun,
11814 int dir, unsigned int flags)
11815{
11816 struct hlua *flt_hlua;
11817 struct hlua_flt_config *conf = FLT_CONF(filter);
11818 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11819 unsigned int hflags = HLUA_TXN_FLT_CTX;
11820 int ret = 1;
11821
11822 flt_hlua = flt_ctx->hlua[(dir == SMP_OPT_DIR_REQ ? 0 : 1)];
11823 if (!flt_hlua)
11824 goto end;
11825
11826 if (!HLUA_IS_RUNNING(flt_hlua)) {
11827 int extra_idx = lua_gettop(flt_hlua->T);
11828
11829 /* The following Lua calls can fail. */
11830 if (!SET_SAFE_LJMP(flt_hlua)) {
11831 const char *error;
11832
11833 if (lua_type(flt_hlua->T, -1) == LUA_TSTRING)
11834 error = lua_tostring(flt_hlua->T, -1);
11835 else
11836 error = "critical error";
11837 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
11838 goto end;
11839 }
11840
11841 /* Check stack size. */
11842 if (!lua_checkstack(flt_hlua->T, 3)) {
11843 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
11844 RESET_SAFE_LJMP(flt_hlua);
11845 goto end;
11846 }
11847
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011848 hlua_pushref(flt_hlua->T, flt_ctx->ref);
Christopher Fauletc404f112020-02-26 15:03:09 +010011849 if (lua_getfield(flt_hlua->T, -1, fun) != LUA_TFUNCTION) {
11850 RESET_SAFE_LJMP(flt_hlua);
11851 goto end;
11852 }
11853 lua_insert(flt_hlua->T, -2);
11854
11855 if (!hlua_txn_new(flt_hlua->T, s, s->be, dir, hflags)) {
11856 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
11857 RESET_SAFE_LJMP(flt_hlua);
11858 goto end;
11859 }
11860 flt_hlua->nargs = 2;
11861
11862 if (flags & HLUA_FLT_CB_ARG_CHN) {
11863 if (dir == SMP_OPT_DIR_REQ)
11864 lua_getfield(flt_hlua->T, -1, "req");
11865 else
11866 lua_getfield(flt_hlua->T, -1, "res");
11867 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
11868 lua_pushstring(flt_hlua->T, "__filter");
11869 lua_pushlightuserdata(flt_hlua->T, filter);
11870 lua_settable(flt_hlua->T, -3);
11871 }
11872 flt_hlua->nargs++;
11873 }
11874 else if (flags & HLUA_FLT_CB_ARG_HTTP_MSG) {
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011875 if (dir == SMP_OPT_DIR_REQ)
11876 lua_getfield(flt_hlua->T, -1, "http_req");
11877 else
11878 lua_getfield(flt_hlua->T, -1, "http_res");
11879 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
11880 lua_pushstring(flt_hlua->T, "__filter");
11881 lua_pushlightuserdata(flt_hlua->T, filter);
11882 lua_settable(flt_hlua->T, -3);
11883 }
11884 flt_hlua->nargs++;
Christopher Fauletc404f112020-02-26 15:03:09 +010011885 }
11886
11887 /* Check stack size. */
11888 if (!lua_checkstack(flt_hlua->T, 1)) {
11889 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
11890 RESET_SAFE_LJMP(flt_hlua);
11891 goto end;
11892 }
11893
11894 while (extra_idx--) {
11895 lua_pushvalue(flt_hlua->T, 1);
11896 lua_remove(flt_hlua->T, 1);
11897 flt_hlua->nargs++;
11898 }
11899
11900 /* We must initialize the execution timeouts. */
Aurelien DARRAGONda9503c2022-11-25 09:10:07 +010011901 hlua_timer_init(&flt_hlua->timer, hlua_timeout_session);
Christopher Fauletc404f112020-02-26 15:03:09 +010011902
11903 /* At this point the execution is safe. */
11904 RESET_SAFE_LJMP(flt_hlua);
11905 }
11906
11907 switch (hlua_ctx_resume(flt_hlua, !(flags & HLUA_FLT_CB_FINAL))) {
11908 case HLUA_E_OK:
11909 /* Catch the return value if it required */
11910 if ((flags & HLUA_FLT_CB_RETVAL) && lua_gettop(flt_hlua->T) > 0) {
11911 ret = lua_tointeger(flt_hlua->T, -1);
11912 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11913 }
11914
11915 /* Set timeout in the required channel. */
11916 if (flt_hlua->wake_time != TICK_ETERNITY) {
11917 if (dir == SMP_OPT_DIR_REQ)
11918 s->req.analyse_exp = flt_hlua->wake_time;
11919 else
11920 s->res.analyse_exp = flt_hlua->wake_time;
11921 }
11922 break;
11923 case HLUA_E_AGAIN:
11924 /* Set timeout in the required channel. */
11925 if (flt_hlua->wake_time != TICK_ETERNITY) {
11926 if (dir == SMP_OPT_DIR_REQ)
11927 s->req.analyse_exp = flt_hlua->wake_time;
11928 else
11929 s->res.analyse_exp = flt_hlua->wake_time;
11930 }
11931 /* Some actions can be wake up when a "write" event
11932 * is detected on a response channel. This is useful
11933 * only for actions targeted on the requests.
11934 */
11935 if (HLUA_IS_WAKERESWR(flt_hlua))
11936 s->res.flags |= CF_WAKE_WRITE;
11937 if (HLUA_IS_WAKEREQWR(flt_hlua))
11938 s->req.flags |= CF_WAKE_WRITE;
11939 ret = 0;
11940 goto end;
11941 case HLUA_E_ERRMSG:
11942 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(flt_hlua->T, -1));
11943 ret = -1;
11944 goto end;
11945 case HLUA_E_ETMOUT:
11946 SEND_ERR(s->be, "Lua filter '%s' : '%s' callback execution timeout.\n", conf->reg->name, fun);
11947 goto end;
11948 case HLUA_E_NOMEM:
11949 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
11950 goto end;
11951 case HLUA_E_YIELD:
11952 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
11953 " are not allowed from '%s' callback.\n", conf->reg->name, fun);
11954 goto end;
11955 case HLUA_E_ERR:
11956 SEND_ERR(s->be, "Lua filter '%s': '%s' returns an unknown error.\n", conf->reg->name, fun);
11957 goto end;
11958 default:
11959 goto end;
11960 }
11961
11962
11963 end:
11964 return ret;
11965}
11966
11967static int hlua_filter_start_analyze(struct stream *s, struct filter *filter, struct channel *chn)
11968{
11969 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11970
11971 flt_ctx->flags = 0;
11972 return hlua_filter_callback(s, filter, "start_analyze",
11973 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11974 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
11975}
11976
11977static int hlua_filter_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
11978{
11979 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11980
11981 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11982 return hlua_filter_callback(s, filter, "end_analyze",
11983 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11984 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
11985}
11986
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011987static int hlua_filter_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
11988{
11989 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11990
11991 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11992 return hlua_filter_callback(s, filter, "http_headers",
11993 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11994 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
11995}
11996
11997static int hlua_filter_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
11998 unsigned int offset, unsigned int len)
11999{
12000 struct hlua_flt_ctx *flt_ctx = filter->ctx;
12001 struct hlua *flt_hlua;
12002 int dir = (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
12003 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
12004 int ret;
12005
12006 flt_hlua = flt_ctx->hlua[idx];
12007 flt_ctx->cur_off[idx] = offset;
12008 flt_ctx->cur_len[idx] = len;
12009 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
12010 ret = hlua_filter_callback(s, filter, "http_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_HTTP_MSG));
12011 if (ret != -1) {
12012 ret = flt_ctx->cur_len[idx];
12013 if (lua_gettop(flt_hlua->T) > 0) {
12014 ret = lua_tointeger(flt_hlua->T, -1);
12015 if (ret > flt_ctx->cur_len[idx])
12016 ret = flt_ctx->cur_len[idx];
12017 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
12018 }
12019 }
12020 return ret;
12021}
12022
12023static int hlua_filter_http_end(struct stream *s, struct filter *filter, struct http_msg *msg)
12024{
12025 struct hlua_flt_ctx *flt_ctx = filter->ctx;
12026
12027 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
12028 return hlua_filter_callback(s, filter, "http_end",
12029 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
12030 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
12031}
12032
Christopher Fauletc404f112020-02-26 15:03:09 +010012033static int hlua_filter_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
12034 unsigned int offset, unsigned int len)
12035{
12036 struct hlua_flt_ctx *flt_ctx = filter->ctx;
12037 struct hlua *flt_hlua;
12038 int dir = (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
12039 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
12040 int ret;
12041
12042 flt_hlua = flt_ctx->hlua[idx];
12043 flt_ctx->cur_off[idx] = offset;
12044 flt_ctx->cur_len[idx] = len;
12045 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
12046 ret = hlua_filter_callback(s, filter, "tcp_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_CHN));
12047 if (ret != -1) {
12048 ret = flt_ctx->cur_len[idx];
12049 if (lua_gettop(flt_hlua->T) > 0) {
12050 ret = lua_tointeger(flt_hlua->T, -1);
12051 if (ret > flt_ctx->cur_len[idx])
12052 ret = flt_ctx->cur_len[idx];
12053 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
12054 }
12055 }
12056 return ret;
12057}
12058
Christopher Faulet69c581a2021-05-31 08:54:04 +020012059static int hlua_filter_parse_fct(char **args, int *cur_arg, struct proxy *px,
12060 struct flt_conf *fconf, char **err, void *private)
12061{
12062 struct hlua_reg_filter *reg_flt = private;
12063 lua_State *L;
12064 struct hlua_flt_config *conf = NULL;
12065 const char *flt_id = NULL;
12066 int state_id, pos, flt_flags = 0;
12067 struct flt_ops *hlua_flt_ops = NULL;
12068
12069 state_id = reg_flt_to_stack_id(reg_flt);
12070 L = hlua_states[state_id];
12071
12072 /* Initialize the filter ops with default callbacks */
12073 hlua_flt_ops = calloc(1, sizeof(*hlua_flt_ops));
Christopher Fauletc86bb872021-08-13 08:33:57 +020012074 if (!hlua_flt_ops)
12075 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012076 hlua_flt_ops->init = hlua_filter_init;
12077 hlua_flt_ops->deinit = hlua_filter_deinit;
12078 if (state_id) {
12079 /* Set per-thread callback if script is loaded per-thread */
12080 hlua_flt_ops->init_per_thread = hlua_filter_init_per_thread;
12081 hlua_flt_ops->deinit_per_thread = hlua_filter_deinit_per_thread;
12082 }
12083 hlua_flt_ops->attach = hlua_filter_new;
12084 hlua_flt_ops->detach = hlua_filter_delete;
12085
12086 /* Push the filter class on the stack and resolve all callbacks */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010012087 hlua_pushref(L, reg_flt->flt_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012088
Christopher Fauletc404f112020-02-26 15:03:09 +010012089 if (lua_getfield(L, -1, "start_analyze") == LUA_TFUNCTION)
12090 hlua_flt_ops->channel_start_analyze = hlua_filter_start_analyze;
12091 lua_pop(L, 1);
12092 if (lua_getfield(L, -1, "end_analyze") == LUA_TFUNCTION)
12093 hlua_flt_ops->channel_end_analyze = hlua_filter_end_analyze;
12094 lua_pop(L, 1);
Christopher Fauleteae8afa2020-02-26 17:15:48 +010012095 if (lua_getfield(L, -1, "http_headers") == LUA_TFUNCTION)
12096 hlua_flt_ops->http_headers = hlua_filter_http_headers;
12097 lua_pop(L, 1);
12098 if (lua_getfield(L, -1, "http_payload") == LUA_TFUNCTION)
12099 hlua_flt_ops->http_payload = hlua_filter_http_payload;
12100 lua_pop(L, 1);
12101 if (lua_getfield(L, -1, "http_end") == LUA_TFUNCTION)
12102 hlua_flt_ops->http_end = hlua_filter_http_end;
12103 lua_pop(L, 1);
Christopher Fauletc404f112020-02-26 15:03:09 +010012104 if (lua_getfield(L, -1, "tcp_payload") == LUA_TFUNCTION)
12105 hlua_flt_ops->tcp_payload = hlua_filter_tcp_payload;
12106 lua_pop(L, 1);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012107
12108 /* Get id and flags of the filter class */
12109 if (lua_getfield(L, -1, "id") == LUA_TSTRING)
12110 flt_id = lua_tostring(L, -1);
12111 lua_pop(L, 1);
12112 if (lua_getfield(L, -1, "flags") == LUA_TNUMBER)
12113 flt_flags = lua_tointeger(L, -1);
12114 lua_pop(L, 1);
12115
12116 /* Create the filter config */
12117 conf = calloc(1, sizeof(*conf));
Christopher Fauletc86bb872021-08-13 08:33:57 +020012118 if (!conf)
Christopher Faulet69c581a2021-05-31 08:54:04 +020012119 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012120 conf->reg = reg_flt;
12121
12122 /* duplicate args */
12123 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++);
12124 conf->args = calloc(pos + 1, sizeof(*conf->args));
Christopher Fauletc86bb872021-08-13 08:33:57 +020012125 if (!conf->args)
12126 goto error;
12127 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020012128 conf->args[pos] = strdup(args[*cur_arg + 1 + pos]);
Christopher Fauletc86bb872021-08-13 08:33:57 +020012129 if (!conf->args[pos])
12130 goto error;
12131 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020012132 conf->args[pos] = NULL;
12133 *cur_arg += pos + 1;
12134
Christopher Fauletc86bb872021-08-13 08:33:57 +020012135 if (flt_id) {
12136 fconf->id = strdup(flt_id);
12137 if (!fconf->id)
12138 goto error;
12139 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020012140 fconf->flags = flt_flags;
12141 fconf->conf = conf;
12142 fconf->ops = hlua_flt_ops;
12143
12144 lua_settop(L, 0);
12145 return 0;
12146
12147 error:
Christopher Fauletc86bb872021-08-13 08:33:57 +020012148 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012149 free(hlua_flt_ops);
Christopher Fauletc86bb872021-08-13 08:33:57 +020012150 if (conf && conf->args) {
12151 for (pos = 0; conf->args[pos]; pos++)
12152 free(conf->args[pos]);
12153 free(conf->args);
12154 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020012155 free(conf);
Christopher Fauletc86bb872021-08-13 08:33:57 +020012156 free((char *)fconf->id);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012157 lua_settop(L, 0);
12158 return -1;
12159}
12160
Christopher Fauletc404f112020-02-26 15:03:09 +010012161__LJMP static int hlua_register_data_filter(lua_State *L)
12162{
12163 struct filter *filter;
12164 struct channel *chn;
12165
12166 MAY_LJMP(check_args(L, 2, "register_data_filter"));
12167 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
12168 chn = MAY_LJMP(hlua_checkchannel(L, 2));
12169
12170 lua_getfield(L, 1, "__filter");
12171 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
12172 filter = lua_touserdata (L, -1);
12173 lua_pop(L, 1);
12174
12175 register_data_filter(chn_strm(chn), chn, filter);
12176 return 1;
12177}
12178
12179__LJMP static int hlua_unregister_data_filter(lua_State *L)
12180{
12181 struct filter *filter;
12182 struct channel *chn;
12183
12184 MAY_LJMP(check_args(L, 2, "unregister_data_filter"));
12185 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
12186 chn = MAY_LJMP(hlua_checkchannel(L, 2));
12187
12188 lua_getfield(L, 1, "__filter");
12189 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
12190 filter = lua_touserdata (L, -1);
12191 lua_pop(L, 1);
12192
12193 unregister_data_filter(chn_strm(chn), chn, filter);
12194 return 1;
12195}
12196
Christopher Faulet69c581a2021-05-31 08:54:04 +020012197/* This function is an LUA binding used for registering a filter. It expects a
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050012198 * filter name used in the haproxy configuration file and a LUA function to
Christopher Faulet69c581a2021-05-31 08:54:04 +020012199 * parse configuration arguments.
12200 */
12201__LJMP static int hlua_register_filter(lua_State *L)
12202{
12203 struct buffer *trash;
12204 struct flt_kw_list *fkl;
12205 struct flt_kw *fkw;
12206 const char *name;
12207 struct hlua_reg_filter *reg_flt= NULL;
12208 int flt_ref, fun_ref;
12209 int len;
12210
12211 MAY_LJMP(check_args(L, 3, "register_filter"));
12212
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010012213 if (hlua_gethlua(L)) {
12214 /* runtime processing */
12215 WILL_LJMP(luaL_error(L, "register_filter: not available outside of body context"));
12216 }
12217
Christopher Faulet69c581a2021-05-31 08:54:04 +020012218 /* First argument : filter name. */
12219 name = MAY_LJMP(luaL_checkstring(L, 1));
12220
12221 /* Second argument : The filter class */
12222 flt_ref = MAY_LJMP(hlua_checktable(L, 2));
12223
12224 /* Third argument : lua function. */
12225 fun_ref = MAY_LJMP(hlua_checkfunction(L, 3));
12226
12227 trash = get_trash_chunk();
12228 chunk_printf(trash, "lua.%s", name);
12229 fkw = flt_find_kw(trash->area);
12230 if (fkw != NULL) {
12231 reg_flt = fkw->private;
12232 if (reg_flt->flt_ref[hlua_state_id] != -1 || reg_flt->fun_ref[hlua_state_id] != -1) {
12233 ha_warning("Trying to register filter 'lua.%s' more than once. "
12234 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010012235 if (reg_flt->flt_ref[hlua_state_id] != -1)
12236 hlua_unref(L, reg_flt->flt_ref[hlua_state_id]);
12237 if (reg_flt->fun_ref[hlua_state_id] != -1)
12238 hlua_unref(L, reg_flt->fun_ref[hlua_state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012239 }
12240 reg_flt->flt_ref[hlua_state_id] = flt_ref;
12241 reg_flt->fun_ref[hlua_state_id] = fun_ref;
12242 return 0;
12243 }
12244
12245 fkl = calloc(1, sizeof(*fkl) + sizeof(struct flt_kw) * 2);
12246 if (!fkl)
12247 goto alloc_error;
12248 fkl->scope = "HLUA";
12249
12250 reg_flt = new_hlua_reg_filter(name);
12251 if (!reg_flt)
12252 goto alloc_error;
12253
12254 reg_flt->flt_ref[hlua_state_id] = flt_ref;
12255 reg_flt->fun_ref[hlua_state_id] = fun_ref;
12256
12257 /* The filter keyword */
12258 len = strlen("lua.") + strlen(name) + 1;
12259 fkl->kw[0].kw = calloc(1, len);
12260 if (!fkl->kw[0].kw)
12261 goto alloc_error;
12262
12263 snprintf((char *)fkl->kw[0].kw, len, "lua.%s", name);
12264
12265 fkl->kw[0].parse = hlua_filter_parse_fct;
12266 fkl->kw[0].private = reg_flt;
12267 memset(&fkl->kw[1], 0, sizeof(*fkl->kw));
12268
12269 /* Register this new filter */
12270 flt_register_keywords(fkl);
12271
12272 return 0;
12273
12274 alloc_error:
12275 release_hlua_reg_filter(reg_flt);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010012276 hlua_unref(L, flt_ref);
12277 hlua_unref(L, fun_ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012278 ha_free(&fkl);
12279 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
12280 return 0; /* Never reached */
12281}
12282
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012283static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012284 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012285 char **err, unsigned int *timeout)
12286{
12287 const char *error;
12288
12289 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +020012290 if (error == PARSE_TIME_OVER) {
12291 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
12292 args[1], args[0]);
12293 return -1;
12294 }
12295 else if (error == PARSE_TIME_UNDER) {
12296 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
12297 args[1], args[0]);
12298 return -1;
12299 }
12300 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012301 memprintf(err, "%s: invalid timeout", args[0]);
12302 return -1;
12303 }
12304 return 0;
12305}
12306
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +020012307static int hlua_burst_timeout(char **args, int section_type, struct proxy *curpx,
12308 const struct proxy *defpx, const char *file, int line,
12309 char **err)
12310{
12311 return hlua_read_timeout(args, section_type, curpx, defpx,
12312 file, line, err, &hlua_timeout_burst);
12313}
12314
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012315static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012316 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012317 char **err)
12318{
12319 return hlua_read_timeout(args, section_type, curpx, defpx,
12320 file, line, err, &hlua_timeout_session);
12321}
12322
12323static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012324 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012325 char **err)
12326{
12327 return hlua_read_timeout(args, section_type, curpx, defpx,
12328 file, line, err, &hlua_timeout_task);
12329}
12330
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012331static int hlua_applet_timeout(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,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012333 char **err)
12334{
12335 return hlua_read_timeout(args, section_type, curpx, defpx,
12336 file, line, err, &hlua_timeout_applet);
12337}
12338
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010012339static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012340 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010012341 char **err)
12342{
12343 char *error;
12344
12345 hlua_nb_instruction = strtoll(args[1], &error, 10);
12346 if (*error != '\0') {
12347 memprintf(err, "%s: invalid number", args[0]);
12348 return -1;
12349 }
12350 return 0;
12351}
12352
Willy Tarreau32f61e22015-03-18 17:54:59 +010012353static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012354 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +010012355 char **err)
12356{
12357 char *error;
12358
12359 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012360 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).", args[0]);
Willy Tarreau32f61e22015-03-18 17:54:59 +010012361 return -1;
12362 }
12363 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
12364 if (*error != '\0') {
12365 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
12366 return -1;
12367 }
12368 return 0;
12369}
12370
12371
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012372/* This function is called by the main configuration key "lua-load". It loads and
12373 * execute an lua file during the parsing of the HAProxy configuration file. It is
12374 * the main lua entry point.
12375 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012376 * This function runs with the HAProxy keywords API. It returns -1 if an error
12377 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012378 *
12379 * In some error case, LUA set an error message in top of the stack. This function
12380 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012381 *
12382 * This function can fail with an abort() due to an Lua critical error.
12383 * We are in the configuration parsing process of HAProxy, this abort() is
12384 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012385 */
Thierry Fournierae6b5682022-09-19 09:04:16 +020012386static int hlua_load_state(char **args, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012387{
12388 int error;
Thierry Fournierae6b5682022-09-19 09:04:16 +020012389 int nargs;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012390
12391 /* Just load and compile the file. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020012392 error = luaL_loadfile(L, args[0]);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012393 if (error) {
Thierry Fournierae6b5682022-09-19 09:04:16 +020012394 memprintf(err, "error in Lua file '%s': %s", args[0], 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 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020012398
12399 /* Push args in the Lua stack, except the first one which is the filename */
12400 for (nargs = 1; *(args[nargs]) != 0; nargs++) {
Aurelien DARRAGON4d7aefe2022-09-23 10:22:14 +020012401 /* Check stack size. */
12402 if (!lua_checkstack(L, 1)) {
12403 memprintf(err, "Lua runtime error while loading arguments: stack is full.");
12404 return -1;
12405 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020012406 lua_pushstring(L, args[nargs]);
12407 }
12408 nargs--;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012409
12410 /* If no syntax error where detected, execute the code. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020012411 error = lua_pcall(L, nargs, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012412 switch (error) {
12413 case LUA_OK:
12414 break;
12415 case LUA_ERRRUN:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012416 memprintf(err, "Lua runtime error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012417 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012418 return -1;
12419 case LUA_ERRMEM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012420 memprintf(err, "Lua out of memory error");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012421 return -1;
12422 case LUA_ERRERR:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012423 memprintf(err, "Lua message handler error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012424 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012425 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020012426#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012427 case LUA_ERRGCMM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012428 memprintf(err, "Lua garbage collector error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012429 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012430 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020012431#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012432 default:
Thierry Fournier70e38e92022-09-19 09:01:53 +020012433 memprintf(err, "Lua unknown error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012434 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012435 return -1;
12436 }
12437
12438 return 0;
12439}
12440
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012441static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012442 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012443 char **err)
12444{
12445 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012446 memprintf(err, "'%s' expects a file name as parameter.", args[0]);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012447 return -1;
12448 }
12449
Thierry Fournier59f11be2020-11-29 00:37:41 +010012450 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +010012451 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012452 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020012453 return hlua_load_state(&args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010012454}
12455
Thierry Fournier59f11be2020-11-29 00:37:41 +010012456static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012457 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +010012458 char **err)
12459{
12460 int len;
Thierry Fournierae6b5682022-09-19 09:04:16 +020012461 int i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012462
12463 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012464 memprintf(err, "'%s' expects a file as parameter.", args[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012465 return -1;
12466 }
12467
12468 if (per_thread_load == NULL) {
12469 /* allocate the first entry large enough to store the final NULL */
12470 per_thread_load = calloc(1, sizeof(*per_thread_load));
12471 if (per_thread_load == NULL) {
12472 memprintf(err, "out of memory error");
12473 return -1;
12474 }
12475 }
12476
12477 /* count used entries */
12478 for (len = 0; per_thread_load[len] != NULL; len++)
12479 ;
12480
12481 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
12482 if (per_thread_load == NULL) {
12483 memprintf(err, "out of memory error");
12484 return -1;
12485 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010012486 per_thread_load[len + 1] = NULL;
12487
Thierry Fournierae6b5682022-09-19 09:04:16 +020012488 /* count args excepting the first, allocate array and copy args */
12489 for (i = 0; *(args[i + 1]) != 0; i++);
Aurelien DARRAGONb12d1692022-09-23 08:48:34 +020012490 per_thread_load[len] = calloc(i + 1, sizeof(*per_thread_load[len]));
Thierry Fournier59f11be2020-11-29 00:37:41 +010012491 if (per_thread_load[len] == NULL) {
12492 memprintf(err, "out of memory error");
12493 return -1;
12494 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020012495 for (i = 1; *(args[i]) != 0; i++) {
12496 per_thread_load[len][i - 1] = strdup(args[i]);
12497 if (per_thread_load[len][i - 1] == NULL) {
12498 memprintf(err, "out of memory error");
12499 return -1;
12500 }
12501 }
12502 per_thread_load[len][i - 1] = strdup("");
12503 if (per_thread_load[len][i - 1] == NULL) {
12504 memprintf(err, "out of memory error");
12505 return -1;
12506 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010012507
12508 /* loading for thread 1 only */
12509 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012510 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020012511 return hlua_load_state(per_thread_load[len], hlua_states[1], err);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012512}
12513
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010012514/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
12515 * in the given <ctx>.
12516 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +010012517static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010012518{
Thierry Fournier3fb9e512020-11-28 10:13:12 +010012519 lua_getglobal(L, "package"); /* push package variable */
12520 lua_pushstring(L, path); /* push given path */
12521 lua_pushstring(L, ";"); /* push semicolon */
12522 lua_getfield(L, -3, type); /* push old path */
12523 lua_concat(L, 3); /* concatenate to new path */
12524 lua_setfield(L, -2, type); /* store new path */
12525 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010012526
12527 return 0;
12528}
12529
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012530static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010012531 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012532 char **err)
12533{
12534 char *path;
12535 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012536 struct prepend_path *p = NULL;
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000012537 size_t i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012538
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012539 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012540 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012541 }
12542
12543 if (!(*args[1])) {
12544 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012545 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012546 }
12547 path = args[1];
12548
12549 if (*args[2]) {
12550 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
12551 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012552 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012553 }
12554 type = args[2];
12555 }
12556
Thierry Fournier59f11be2020-11-29 00:37:41 +010012557 p = calloc(1, sizeof(*p));
12558 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010012559 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012560 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012561 }
12562 p->path = strdup(path);
12563 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010012564 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012565 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012566 }
12567 p->type = strdup(type);
12568 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010012569 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012570 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012571 }
Willy Tarreau2b718102021-04-21 07:32:39 +020012572 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012573
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020012574 /* Handle the global state and the per-thread state for the first
12575 * thread. The remaining threads will be initialized based on
12576 * prepend_path_list.
12577 */
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000012578 for (i = 0; i < 2; i++) {
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020012579 lua_State *L = hlua_states[i];
12580 const char *error;
12581
12582 if (setjmp(safe_ljmp_env) != 0) {
12583 lua_atpanic(L, hlua_panic_safe);
12584 if (lua_type(L, -1) == LUA_TSTRING)
12585 error = lua_tostring(L, -1);
12586 else
12587 error = "critical error";
12588 fprintf(stderr, "lua-prepend-path: %s.\n", error);
12589 exit(1);
12590 } else {
12591 lua_atpanic(L, hlua_panic_ljmp);
12592 }
12593
12594 hlua_prepend_path(L, type, path);
12595
12596 lua_atpanic(L, hlua_panic_safe);
12597 }
12598
Thierry Fournier59f11be2020-11-29 00:37:41 +010012599 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +010012600
12601err2:
12602 free(p->type);
12603 free(p->path);
12604err:
12605 free(p);
12606 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012607}
12608
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012609/* configuration keywords declaration */
12610static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010012611 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012612 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +010012613 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010012614 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
12615 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +020012616 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Aurelien DARRAGON58e36e52023-04-06 22:51:56 +020012617 { CFG_GLOBAL, "tune.lua.burst-timeout", hlua_burst_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010012618 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +010012619 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010012620 { 0, NULL, NULL },
12621}};
12622
Willy Tarreau0108d902018-11-25 19:14:37 +010012623INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
12624
William Lallemand52139182022-03-30 15:05:42 +020012625#ifdef USE_OPENSSL
Christopher Fauletafd8f102018-11-08 11:34:21 +010012626
William Lallemand30fcca12022-03-30 12:03:12 +020012627/*
12628 * This function replace a ckch_store by another one, and rebuild the ckch_inst and all its dependencies.
12629 * It does the sam as "cli_io_handler_commit_cert" but for lua, the major
12630 * difference is that the yield in lua and for the CLI is not handled the same
12631 * way.
12632 */
12633__LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext ctx)
12634{
12635 struct ckch_inst **lua_ckchi = lua_touserdata(L, -1);
12636 struct ckch_store **lua_ckchs = lua_touserdata(L, -2);
12637 struct ckch_inst *ckchi = *lua_ckchi;
12638 struct ckch_store *old_ckchs = lua_ckchs[0];
12639 struct ckch_store *new_ckchs = lua_ckchs[1];
12640 struct hlua *hlua;
12641 char *err = NULL;
12642 int y = 1;
12643
12644 hlua = hlua_gethlua(L);
12645
12646 /* get the first ckchi to copy */
12647 if (ckchi == NULL)
12648 ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
12649
12650 /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
12651 list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
12652 struct ckch_inst *new_inst;
12653
12654 /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
12655 if (y % 10 == 0) {
12656
12657 *lua_ckchi = ckchi;
12658
12659 task_wakeup(hlua->task, TASK_WOKEN_MSG);
12660 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
12661 }
12662
12663 if (ckch_inst_rebuild(new_ckchs, ckchi, &new_inst, &err))
12664 goto error;
12665
12666 /* link the new ckch_inst to the duplicate */
12667 LIST_APPEND(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
12668 y++;
12669 }
12670
12671 /* The generation is finished, we can insert everything */
12672 ckch_store_replace(old_ckchs, new_ckchs);
12673
12674 lua_pop(L, 2); /* pop the lua_ckchs and ckchi */
12675
12676 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
12677
12678 return 0;
12679
12680error:
12681 ckch_store_free(new_ckchs);
12682 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
12683 WILL_LJMP(luaL_error(L, "%s", err));
12684 free(err);
12685
12686 return 0;
12687}
12688
12689/*
12690 * Replace a ckch_store <filename> in the ckchs_tree with a ckch_store created
12691 * from the table in parameter.
12692 *
12693 * This is equivalent to "set ssl cert" + "commit ssl cert" over the CLI, which
12694 * means it does not need to have a transaction since everything is done in the
12695 * same function.
12696 *
12697 * CertCache.set{filename="", crt="", key="", sctl="", ocsp="", issuer=""}
12698 *
12699 */
12700__LJMP static int hlua_ckch_set(lua_State *L)
12701{
12702 struct hlua *hlua;
12703 struct ckch_inst **lua_ckchi;
12704 struct ckch_store **lua_ckchs;
12705 struct ckch_store *old_ckchs = NULL;
12706 struct ckch_store *new_ckchs = NULL;
12707 int errcode = 0;
12708 char *err = NULL;
12709 struct cert_exts *cert_ext = NULL;
12710 char *filename;
William Lallemand52ddd992022-11-22 11:51:53 +010012711 struct ckch_data *data;
William Lallemand30fcca12022-03-30 12:03:12 +020012712 int ret;
12713
12714 if (lua_type(L, -1) != LUA_TTABLE)
12715 WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
12716
12717 hlua = hlua_gethlua(L);
12718
12719 /* FIXME: this should not return an error but should come back later */
12720 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
12721 WILL_LJMP(luaL_error(L, "CertCache already under lock"));
12722
12723 ret = lua_getfield(L, -1, "filename");
12724 if (ret != LUA_TSTRING) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012725 memprintf(&err, "%sNo filename specified!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020012726 errcode |= ERR_ALERT | ERR_FATAL;
12727 goto end;
12728 }
12729 filename = (char *)lua_tostring(L, -1);
12730
12731
12732 /* look for the filename in the tree */
12733 old_ckchs = ckchs_lookup(filename);
12734 if (!old_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012735 memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020012736 errcode |= ERR_ALERT | ERR_FATAL;
12737 goto end;
12738 }
12739 /* TODO: handle extra_files_noext */
12740
12741 new_ckchs = ckchs_dup(old_ckchs);
12742 if (!new_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012743 memprintf(&err, "%sCannot allocate memory!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020012744 errcode |= ERR_ALERT | ERR_FATAL;
12745 goto end;
12746 }
12747
William Lallemand52ddd992022-11-22 11:51:53 +010012748 data = new_ckchs->data;
William Lallemand30fcca12022-03-30 12:03:12 +020012749
12750 /* loop on the field in the table, which have the same name as the
12751 * possible extensions of files */
12752 lua_pushnil(L);
12753 while (lua_next(L, 1)) {
12754 int i;
12755 const char *field = lua_tostring(L, -2);
12756 char *payload = (char *)lua_tostring(L, -1);
12757
12758 if (!field || strcmp(field, "filename") == 0) {
12759 lua_pop(L, 1);
12760 continue;
12761 }
12762
12763 for (i = 0; field && cert_exts[i].ext != NULL; i++) {
12764 if (strcmp(field, cert_exts[i].ext) == 0) {
12765 cert_ext = &cert_exts[i];
12766 break;
12767 }
12768 }
12769
12770 /* this is the default type, the field is not supported */
12771 if (cert_ext == NULL) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012772 memprintf(&err, "%sUnsupported field '%s'", err ? err : "", field);
William Lallemand30fcca12022-03-30 12:03:12 +020012773 errcode |= ERR_ALERT | ERR_FATAL;
12774 goto end;
12775 }
12776
12777 /* appply the change on the duplicate */
William Lallemand52ddd992022-11-22 11:51:53 +010012778 if (cert_ext->load(filename, payload, data, &err) != 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020012779 memprintf(&err, "%sCan't load the payload for '%s'", err ? err : "", cert_ext->ext);
William Lallemand30fcca12022-03-30 12:03:12 +020012780 errcode |= ERR_ALERT | ERR_FATAL;
12781 goto end;
12782 }
12783 lua_pop(L, 1);
12784 }
12785
12786 /* store the pointers on the lua stack */
12787 lua_ckchs = lua_newuserdata(L, sizeof(struct ckch_store *) * 2);
12788 lua_ckchs[0] = old_ckchs;
12789 lua_ckchs[1] = new_ckchs;
12790 lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
12791 *lua_ckchi = NULL;
12792
12793 task_wakeup(hlua->task, TASK_WOKEN_MSG);
12794 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
12795
12796end:
12797 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
12798
12799 if (errcode & ERR_CODE) {
12800 ckch_store_free(new_ckchs);
12801 WILL_LJMP(luaL_error(L, "%s", err));
12802 }
12803 free(err);
12804
12805 return 0;
12806}
12807
William Lallemand52139182022-03-30 15:05:42 +020012808#else
12809
12810__LJMP static int hlua_ckch_set(lua_State *L)
12811{
12812 WILL_LJMP(luaL_error(L, "'CertCache.set' needs an HAProxy built with OpenSSL"));
12813
12814 return 0;
12815}
12816#endif /* ! USE_OPENSSL */
12817
12818
12819
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012820/* This function can fail with an abort() due to an Lua critical error.
12821 * We are in the initialisation process of HAProxy, this abort() is
12822 * tolerated.
12823 */
Thierry Fournierb8cef172020-11-28 15:37:17 +010012824int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012825{
12826 struct hlua_init_function *init;
12827 const char *msg;
12828 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +010012829 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +010012830 const char *kind;
12831 const char *trace;
12832 int return_status = 1;
12833#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
12834 int nres;
12835#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012836
Willy Tarreaucdb53462020-12-02 12:12:00 +010012837 /* disable memory limit checks if limit is not set */
12838 if (!hlua_global_allocator.limit)
12839 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
12840
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050012841 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +010012842 if (setjmp(safe_ljmp_env) != 0) {
12843 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +010012844 if (lua_type(L, -1) == LUA_TSTRING)
12845 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010012846 else
12847 error = "critical error";
12848 fprintf(stderr, "Lua post-init: %s.\n", error);
12849 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010012850 } else {
12851 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010012852 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +020012853
Thierry Fournierc7492592020-11-28 23:57:24 +010012854 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010012855 hlua_pushref(L, init->function_ref);
Aurelien DARRAGON16d047b2023-03-20 16:29:55 +010012856 /* function ref should be released right away since it was pushed
12857 * on the stack and will not be used anymore
12858 */
12859 hlua_unref(L, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +010012860
12861#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +010012862 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +010012863#else
Thierry Fournierb8cef172020-11-28 15:37:17 +010012864 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +010012865#endif
12866 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012867 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +010012868
12869 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +010012870 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +010012871 break;
Thierry Fournier670db242020-11-28 10:49:59 +010012872
12873 case LUA_ERRERR:
12874 kind = "message handler error";
Willy Tarreau14de3952022-11-14 07:08:28 +010012875 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010012876 case LUA_ERRRUN:
12877 if (!kind)
12878 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010012879 msg = lua_tostring(L, -1);
12880 lua_settop(L, 0); /* Empty the stack. */
Christopher Fauletd09cc512021-03-24 14:48:45 +010012881 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010012882 if (msg)
12883 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
12884 else
12885 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
12886 return_status = 0;
12887 break;
12888
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012889 default:
Thierry Fournier670db242020-11-28 10:49:59 +010012890 /* Unknown error */
12891 kind = "Unknown error";
Willy Tarreau14de3952022-11-14 07:08:28 +010012892 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010012893 case LUA_YIELD:
12894 /* yield is not configured at this step, this state doesn't happen */
12895 if (!kind)
12896 kind = "yield not allowed";
Willy Tarreau14de3952022-11-14 07:08:28 +010012897 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010012898 case LUA_ERRMEM:
12899 if (!kind)
12900 kind = "out of memory error";
Aurelien DARRAGON3e81aed2023-08-09 10:11:49 +020012901 lua_settop(L, 0); /* Empty the stack. */
Christopher Fauletd09cc512021-03-24 14:48:45 +010012902 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010012903 ha_alert("Lua init: %s: %s\n", kind, trace);
12904 return_status = 0;
12905 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012906 }
Thierry Fournier670db242020-11-28 10:49:59 +010012907 if (!return_status)
12908 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012909 }
Thierry Fournier3c539322020-11-28 16:05:05 +010012910
12911 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +010012912 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012913}
12914
Thierry Fournierb8cef172020-11-28 15:37:17 +010012915int hlua_post_init()
12916{
Thierry Fournier59f11be2020-11-29 00:37:41 +010012917 int ret;
12918 int i;
12919 int errors;
12920 char *err = NULL;
12921 struct hlua_function *fcn;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012922 struct hlua_reg_filter *reg_flt;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012923
Willy Tarreaub1310492021-08-30 09:35:18 +020012924#if defined(USE_OPENSSL)
Thierry Fournierb8cef172020-11-28 15:37:17 +010012925 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012926 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010012927 int saved_used_backed = global.ssl_used_backend;
12928 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012929 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +010012930 global.ssl_used_backend = saved_used_backed;
12931 }
12932#endif
12933
Thierry Fournierc7492592020-11-28 23:57:24 +010012934 /* Perform post init of common thread */
12935 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012936 ha_set_thread(&ha_thread_info[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012937 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
12938 if (ret == 0)
12939 return 0;
12940
12941 /* init remaining lua states and load files */
12942 for (hlua_state_id = 2; 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 /* Init lua state */
12948 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
12949
12950 /* Load lua files */
12951 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
12952 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
12953 if (ret != 0) {
12954 ha_alert("Lua init: %s\n", err);
12955 return 0;
12956 }
12957 }
12958 }
12959
12960 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012961 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012962
12963 /* Execute post init for all states */
12964 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
12965
12966 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012967 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012968
12969 /* run post init */
12970 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
12971 if (ret == 0)
12972 return 0;
12973 }
12974
12975 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012976 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012977
12978 /* control functions registering. Each function must have:
12979 * - only the function_ref[0] set positive and all other to -1
12980 * - only the function_ref[0] set to -1 and all other positive
12981 * This ensure a same reference is not used both in shared
12982 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050012983 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +010012984 * complicated to found for the end user.
12985 */
12986 errors = 0;
12987 list_for_each_entry(fcn, &referenced_functions, l) {
12988 ret = 0;
12989 for (i = 1; i < global.nbthread + 1; i++) {
12990 if (fcn->function_ref[i] == -1)
12991 ret--;
12992 else
12993 ret++;
12994 }
12995 if (abs(ret) != global.nbthread) {
12996 ha_alert("Lua function '%s' is not referenced in all thread. "
12997 "Expect function in all thread or in none thread.\n", fcn->name);
12998 errors++;
12999 continue;
13000 }
13001
13002 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050013003 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
13004 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +010013005 "exclusive.\n", fcn->name);
13006 errors++;
13007 }
13008 }
13009
Christopher Faulet69c581a2021-05-31 08:54:04 +020013010 /* Do the same with registered filters */
13011 list_for_each_entry(reg_flt, &referenced_filters, l) {
13012 ret = 0;
13013 for (i = 1; i < global.nbthread + 1; i++) {
13014 if (reg_flt->flt_ref[i] == -1)
13015 ret--;
13016 else
13017 ret++;
13018 }
13019 if (abs(ret) != global.nbthread) {
13020 ha_alert("Lua filter '%s' is not referenced in all thread. "
13021 "Expect function in all thread or in none thread.\n", reg_flt->name);
13022 errors++;
13023 continue;
13024 }
13025
13026 if ((reg_flt->flt_ref[0] == -1) == (ret < 0)) {
13027 ha_alert("Lua filter '%s' is referenced both ins shared Lua context (through lua-load) "
13028 "and per-thread Lua context (through lua-load-per-thread). these two context "
13029 "exclusive.\n", fcn->name);
13030 errors++;
13031 }
13032 }
13033
13034
Thierry Fournier59f11be2020-11-29 00:37:41 +010013035 if (errors > 0)
13036 return 0;
13037
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050013038 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +010013039 * -1 in order to have probably a segfault if someone use it
13040 */
13041 hlua_state_id = -1;
13042
13043 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +010013044}
13045
Willy Tarreau32f61e22015-03-18 17:54:59 +010013046/* The memory allocator used by the Lua stack. <ud> is a pointer to the
13047 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
13048 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010013049 * allocation. <nsize> is the requested new size. A new allocation is
13050 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +010013051 * zero. This one verifies that the limits are respected but is optimized
13052 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreaua5efdff2021-10-22 16:00:02 +020013053 *
13054 * Warning: while this API ressembles glibc's realloc() a lot, glibc surpasses
13055 * POSIX by making realloc(ptr,0) an effective free(), but others do not do
13056 * that and will simply allocate zero as if it were the result of malloc(0),
13057 * so mapping this onto realloc() will lead to memory leaks on non-glibc
13058 * systems.
Willy Tarreau32f61e22015-03-18 17:54:59 +010013059 */
13060static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
13061{
13062 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +010013063 size_t limit, old, new;
13064
13065 /* a limit of ~0 means unlimited and boot complete, so there's no need
13066 * for accounting anymore.
13067 */
Willy Tarreaua5efdff2021-10-22 16:00:02 +020013068 if (likely(~zone->limit == 0)) {
13069 if (!nsize)
13070 ha_free(&ptr);
13071 else
13072 ptr = realloc(ptr, nsize);
13073 return ptr;
13074 }
Willy Tarreau32f61e22015-03-18 17:54:59 +010013075
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010013076 if (!ptr)
13077 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +010013078
Willy Tarreaucdb53462020-12-02 12:12:00 +010013079 /* enforce strict limits across all threads */
13080 limit = zone->limit;
13081 old = _HA_ATOMIC_LOAD(&zone->allocated);
13082 do {
13083 new = old + nsize - osize;
13084 if (unlikely(nsize && limit && new > limit))
13085 return NULL;
13086 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +010013087
Willy Tarreaua5efdff2021-10-22 16:00:02 +020013088 if (!nsize)
13089 ha_free(&ptr);
13090 else
13091 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +010013092
13093 if (unlikely(!ptr && nsize)) // failed
13094 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
13095
13096 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +010013097 return ptr;
13098}
13099
Thierry Fournierecb83c22020-11-28 15:49:44 +010013100/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020013101 * We are in the initialisation process of HAProxy, this abort() is
13102 * tolerated.
13103 */
Thierry Fournierecb83c22020-11-28 15:49:44 +010013104lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010013105{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013106 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013107 int idx;
13108 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013109 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013110 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +010013111 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +010013112 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013113 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +010013114 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013115
Thierry FOURNIER380d0932015-01-23 14:27:52 +010013116 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013117 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +010013118
firexinghe64d7afb2023-07-13 11:03:34 +080013119 if (!L) {
13120 fprintf(stderr,
13121 "Lua init: critical error: lua_newstate() returned NULL."
13122 " This may possibly be caused by a memory allocation error.\n");
13123 exit(1);
13124 }
13125
Thierry Fournier4234dbd2020-11-28 13:18:23 +010013126 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013127 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +010013128 *context = NULL;
13129
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080013130 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +020013131 * the Lua function can fail with an abort. We are in the initialisation
13132 * process of HAProxy, this abort() is tolerated.
13133 */
13134
Thierry Fournier3c539322020-11-28 16:05:05 +010013135 /* Call post initialisation function in safe environment. */
13136 if (setjmp(safe_ljmp_env) != 0) {
13137 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013138 if (lua_type(L, -1) == LUA_TSTRING)
13139 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010013140 else
13141 error_msg = "critical error";
13142 fprintf(stderr, "Lua init: %s.\n", error_msg);
13143 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010013144 } else {
13145 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010013146 }
13147
Thierry FOURNIER380d0932015-01-23 14:27:52 +010013148 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013149 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010013150#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
13151#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
13152#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013153 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010013154#endif
13155#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013156 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010013157#endif
13158#undef HLUA_PREPEND_PATH_TOSTRING
13159#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013160
Thierry Fournier59f11be2020-11-29 00:37:41 +010013161 /* Apply configured prepend path */
13162 list_for_each_entry(pp, &prepend_path_list, l)
13163 hlua_prepend_path(L, pp->type, pp->path);
13164
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013165 /*
Aurelien DARRAGON8cd620b2023-04-07 17:37:46 +020013166 * Override some lua functions.
13167 *
13168 */
13169
13170 /* push our "safe" coroutine.create() function */
13171 lua_getglobal(L, "coroutine");
13172 lua_pushcclosure(L, hlua_coroutine_create, 0);
13173 lua_setfield(L, -2, "create");
13174
13175 /*
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013176 *
13177 * Create "core" object.
13178 *
13179 */
13180
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +010013181 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013182 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013183
Thierry Fournierecb83c22020-11-28 15:49:44 +010013184 /* set the thread id */
13185 hlua_class_const_int(L, "thread", thread_num);
13186
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013187 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +010013188 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013189 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010013190
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010013191 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013192 hlua_class_function(L, "register_init", hlua_register_init);
13193 hlua_class_function(L, "register_task", hlua_register_task);
13194 hlua_class_function(L, "register_fetches", hlua_register_fetches);
13195 hlua_class_function(L, "register_converters", hlua_register_converters);
13196 hlua_class_function(L, "register_action", hlua_register_action);
13197 hlua_class_function(L, "register_service", hlua_register_service);
13198 hlua_class_function(L, "register_cli", hlua_register_cli);
Christopher Faulet69c581a2021-05-31 08:54:04 +020013199 hlua_class_function(L, "register_filter", hlua_register_filter);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013200 hlua_class_function(L, "yield", hlua_yield);
13201 hlua_class_function(L, "set_nice", hlua_set_nice);
13202 hlua_class_function(L, "sleep", hlua_sleep);
13203 hlua_class_function(L, "msleep", hlua_msleep);
13204 hlua_class_function(L, "add_acl", hlua_add_acl);
13205 hlua_class_function(L, "del_acl", hlua_del_acl);
13206 hlua_class_function(L, "set_map", hlua_set_map);
13207 hlua_class_function(L, "del_map", hlua_del_map);
13208 hlua_class_function(L, "tcp", hlua_socket_new);
William Lallemand3956c4e2021-09-21 16:25:15 +020013209 hlua_class_function(L, "httpclient", hlua_httpclient_new);
Aurelien DARRAGONc84899c2023-02-20 18:18:59 +010013210 hlua_class_function(L, "event_sub", hlua_event_global_sub);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013211 hlua_class_function(L, "log", hlua_log);
13212 hlua_class_function(L, "Debug", hlua_log_debug);
13213 hlua_class_function(L, "Info", hlua_log_info);
13214 hlua_class_function(L, "Warning", hlua_log_warning);
13215 hlua_class_function(L, "Alert", hlua_log_alert);
13216 hlua_class_function(L, "done", hlua_done);
Aurelien DARRAGON5bed48f2023-04-21 17:32:46 +020013217 hlua_class_function(L, "disable_legacy_mailers", hlua_disable_legacy_mailers);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013218 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010013219
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013220 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013221
13222 /*
13223 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013224 * Create "act" object.
13225 *
13226 */
13227
13228 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013229 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013230
13231 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013232 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
13233 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
13234 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
13235 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
13236 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
13237 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
13238 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
13239 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013240
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013241 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010013242
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013243 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +010013244
13245 /*
13246 *
Christopher Faulet69c581a2021-05-31 08:54:04 +020013247 * Create "Filter" object.
13248 *
13249 */
13250
13251 /* This table entry is the object "filter" base. */
13252 lua_newtable(L);
13253
13254 /* push flags and constants */
13255 hlua_class_const_int(L, "CONTINUE", 1);
13256 hlua_class_const_int(L, "WAIT", 0);
13257 hlua_class_const_int(L, "ERROR", -1);
13258
13259 hlua_class_const_int(L, "FLT_CFG_FL_HTX", FLT_CFG_FL_HTX);
13260
Christopher Fauletc404f112020-02-26 15:03:09 +010013261 hlua_class_function(L, "wake_time", hlua_set_wake_time);
13262 hlua_class_function(L, "register_data_filter", hlua_register_data_filter);
13263 hlua_class_function(L, "unregister_data_filter", hlua_unregister_data_filter);
13264
Christopher Faulet69c581a2021-05-31 08:54:04 +020013265 lua_setglobal(L, "filter");
13266
13267 /*
13268 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013269 * Register class Map
13270 *
13271 */
13272
13273 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013274 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013275
13276 /* register pattern types. */
13277 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013278 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010013279 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020013280 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013281 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010013282 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013283
13284 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013285 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013286
13287 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013288 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013289
Ilya Shipitsind4259502020-04-08 01:07:56 +050013290 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013291 lua_pushstring(L, "__index");
13292 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013293
13294 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013295 hlua_class_function(L, "lookup", hlua_map_lookup);
13296 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013297
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013298 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013299
Thierry Fournier45e78d72016-02-19 18:34:46 +010013300 /* Register previous table in the registry with reference and named entry.
13301 * The function hlua_register_metatable() pops the stack, so we
13302 * previously create a copy of the table.
13303 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013304 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
13305 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013306
13307 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013308 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013309
13310 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013311 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +020013312
13313 /*
13314 *
William Lallemand30fcca12022-03-30 12:03:12 +020013315 * Register "CertCache" class
13316 *
13317 */
13318
13319 /* Create and fill the metatable. */
13320 lua_newtable(L);
13321 /* Register */
13322 hlua_class_function(L, "set", hlua_ckch_set);
13323 lua_setglobal(L, CLASS_CERTCACHE); /* Create global object called Regex */
13324
13325 /*
13326 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013327 * Register class Channel
13328 *
13329 */
13330
13331 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013332 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013333
Ilya Shipitsind4259502020-04-08 01:07:56 +050013334 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013335 lua_pushstring(L, "__index");
13336 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013337
13338 /* Register . */
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013339 hlua_class_function(L, "data", hlua_channel_get_data);
13340 hlua_class_function(L, "line", hlua_channel_get_line);
13341 hlua_class_function(L, "set", hlua_channel_set_data);
13342 hlua_class_function(L, "remove", hlua_channel_del_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013343 hlua_class_function(L, "append", hlua_channel_append);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013344 hlua_class_function(L, "prepend", hlua_channel_prepend);
13345 hlua_class_function(L, "insert", hlua_channel_insert_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013346 hlua_class_function(L, "send", hlua_channel_send);
13347 hlua_class_function(L, "forward", hlua_channel_forward);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013348 hlua_class_function(L, "input", hlua_channel_get_in_len);
13349 hlua_class_function(L, "output", hlua_channel_get_out_len);
13350 hlua_class_function(L, "may_recv", hlua_channel_may_recv);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013351 hlua_class_function(L, "is_full", hlua_channel_is_full);
13352 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013353
Christopher Faulet6a79fc12021-08-06 16:02:36 +020013354 /* Deprecated API */
13355 hlua_class_function(L, "get", hlua_channel_get);
13356 hlua_class_function(L, "dup", hlua_channel_dup);
13357 hlua_class_function(L, "getline", hlua_channel_getline);
13358 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
13359 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
13360
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013361 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013362
13363 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013364 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010013365
13366 /*
13367 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013368 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013369 *
13370 */
13371
13372 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013373 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013374
Ilya Shipitsind4259502020-04-08 01:07:56 +050013375 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013376 lua_pushstring(L, "__index");
13377 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013378
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013379 /* Browse existing fetches and create the associated
13380 * object method.
13381 */
13382 sf = NULL;
13383 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013384 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
13385 * by an underscore.
13386 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020013387 strlcpy2(trash.area, sf->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020013388 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013389 if (*p == '.' || *p == '-' || *p == '+')
13390 *p = '_';
13391
13392 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013393 lua_pushstring(L, trash.area);
13394 lua_pushlightuserdata(L, sf);
13395 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
13396 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010013397 }
13398
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013399 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013400
13401 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013402 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013403
13404 /*
13405 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013406 * Register class Converters
13407 *
13408 */
13409
13410 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013411 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013412
13413 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013414 lua_pushstring(L, "__index");
13415 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013416
13417 /* Browse existing converters and create the associated
13418 * object method.
13419 */
13420 sc = NULL;
13421 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013422 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
13423 * by an underscore.
13424 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020013425 strlcpy2(trash.area, sc->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020013426 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013427 if (*p == '.' || *p == '-' || *p == '+')
13428 *p = '_';
13429
13430 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013431 lua_pushstring(L, trash.area);
13432 lua_pushlightuserdata(L, sc);
13433 lua_pushcclosure(L, hlua_run_sample_conv, 1);
13434 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013435 }
13436
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013437 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013438
13439 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013440 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010013441
13442 /*
13443 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013444 * Register class HTTP
13445 *
13446 */
13447
13448 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013449 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013450
Ilya Shipitsind4259502020-04-08 01:07:56 +050013451 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013452 lua_pushstring(L, "__index");
13453 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013454
13455 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013456 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
13457 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
13458 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
13459 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
13460 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
13461 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
13462 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
13463 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
13464 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
13465 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013466
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013467 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
13468 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
13469 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
13470 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
13471 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
13472 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
13473 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013474
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013475 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013476
13477 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013478 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013479
Christopher Fauletdf97ac42020-02-26 16:57:19 +010013480 /*
13481 *
13482 * Register class HTTPMessage
13483 *
13484 */
13485
13486 /* Create and fill the metatable. */
13487 lua_newtable(L);
13488
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050013489 /* Create and fill the __index entry. */
Christopher Fauletdf97ac42020-02-26 16:57:19 +010013490 lua_pushstring(L, "__index");
13491 lua_newtable(L);
13492
13493 /* Register Lua functions. */
13494 hlua_class_function(L, "is_resp", hlua_http_msg_is_resp);
13495 hlua_class_function(L, "get_stline", hlua_http_msg_get_stline);
13496 hlua_class_function(L, "get_headers", hlua_http_msg_get_headers);
13497 hlua_class_function(L, "del_header", hlua_http_msg_del_hdr);
13498 hlua_class_function(L, "rep_header", hlua_http_msg_rep_hdr);
13499 hlua_class_function(L, "rep_value", hlua_http_msg_rep_val);
13500 hlua_class_function(L, "add_header", hlua_http_msg_add_hdr);
13501 hlua_class_function(L, "set_header", hlua_http_msg_set_hdr);
13502 hlua_class_function(L, "set_method", hlua_http_msg_set_meth);
13503 hlua_class_function(L, "set_path", hlua_http_msg_set_path);
13504 hlua_class_function(L, "set_query", hlua_http_msg_set_query);
13505 hlua_class_function(L, "set_uri", hlua_http_msg_set_uri);
13506 hlua_class_function(L, "set_status", hlua_http_msg_set_status);
13507 hlua_class_function(L, "is_full", hlua_http_msg_is_full);
13508 hlua_class_function(L, "may_recv", hlua_http_msg_may_recv);
13509 hlua_class_function(L, "eom", hlua_http_msg_is_eom);
13510 hlua_class_function(L, "input", hlua_http_msg_get_in_len);
13511 hlua_class_function(L, "output", hlua_http_msg_get_out_len);
13512
13513 hlua_class_function(L, "body", hlua_http_msg_get_body);
13514 hlua_class_function(L, "set", hlua_http_msg_set_data);
13515 hlua_class_function(L, "remove", hlua_http_msg_del_data);
13516 hlua_class_function(L, "append", hlua_http_msg_append);
13517 hlua_class_function(L, "prepend", hlua_http_msg_prepend);
13518 hlua_class_function(L, "insert", hlua_http_msg_insert_data);
13519 hlua_class_function(L, "set_eom", hlua_http_msg_set_eom);
13520 hlua_class_function(L, "unset_eom", hlua_http_msg_unset_eom);
13521
13522 hlua_class_function(L, "send", hlua_http_msg_send);
13523 hlua_class_function(L, "forward", hlua_http_msg_forward);
13524
13525 lua_rawset(L, -3);
13526
13527 /* Register previous table in the registry with reference and named entry. */
13528 class_http_msg_ref = hlua_register_metatable(L, CLASS_HTTP_MSG);
William Lallemand3956c4e2021-09-21 16:25:15 +020013529
13530 /*
13531 *
13532 * Register class HTTPClient
13533 *
13534 */
13535
13536 /* Create and fill the metatable. */
13537 lua_newtable(L);
13538 lua_pushstring(L, "__index");
13539 lua_newtable(L);
13540 hlua_class_function(L, "get", hlua_httpclient_get);
William Lallemanddc2cc902021-10-26 11:43:26 +020013541 hlua_class_function(L, "head", hlua_httpclient_head);
13542 hlua_class_function(L, "put", hlua_httpclient_put);
13543 hlua_class_function(L, "post", hlua_httpclient_post);
13544 hlua_class_function(L, "delete", hlua_httpclient_delete);
William Lallemand3956c4e2021-09-21 16:25:15 +020013545 lua_settable(L, -3); /* Sets the __index entry. */
William Lallemandf77f1de2021-09-28 19:10:38 +020013546 /* Register the garbage collector entry. */
13547 lua_pushstring(L, "__gc");
13548 lua_pushcclosure(L, hlua_httpclient_gc, 0);
13549 lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
13550
William Lallemand3956c4e2021-09-21 16:25:15 +020013551
13552
13553 class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010013554 /*
13555 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013556 * Register class AppletTCP
13557 *
13558 */
13559
13560 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013561 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013562
Ilya Shipitsind4259502020-04-08 01:07:56 +050013563 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013564 lua_pushstring(L, "__index");
13565 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013566
13567 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013568 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
13569 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
13570 hlua_class_function(L, "send", hlua_applet_tcp_send);
13571 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
13572 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
13573 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
13574 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
13575 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013576
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013577 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013578
13579 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013580 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020013581
13582 /*
13583 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013584 * Register class AppletHTTP
13585 *
13586 */
13587
13588 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013589 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013590
Ilya Shipitsind4259502020-04-08 01:07:56 +050013591 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013592 lua_pushstring(L, "__index");
13593 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013594
13595 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013596 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
13597 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
13598 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
13599 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
13600 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
13601 hlua_class_function(L, "getline", hlua_applet_http_getline);
13602 hlua_class_function(L, "receive", hlua_applet_http_recv);
13603 hlua_class_function(L, "send", hlua_applet_http_send);
13604 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
13605 hlua_class_function(L, "set_status", hlua_applet_http_status);
13606 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013607
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013608 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013609
13610 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013611 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020013612
13613 /*
13614 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013615 * Register class TXN
13616 *
13617 */
13618
13619 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013620 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013621
Ilya Shipitsind4259502020-04-08 01:07:56 +050013622 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013623 lua_pushstring(L, "__index");
13624 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010013625
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010013626 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013627 hlua_class_function(L, "set_priv", hlua_set_priv);
13628 hlua_class_function(L, "get_priv", hlua_get_priv);
13629 hlua_class_function(L, "set_var", hlua_set_var);
13630 hlua_class_function(L, "unset_var", hlua_unset_var);
13631 hlua_class_function(L, "get_var", hlua_get_var);
13632 hlua_class_function(L, "done", hlua_txn_done);
13633 hlua_class_function(L, "reply", hlua_txn_reply_new);
13634 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
13635 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
13636 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
13637 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
13638 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
13639 hlua_class_function(L, "deflog", hlua_txn_deflog);
13640 hlua_class_function(L, "log", hlua_txn_log);
13641 hlua_class_function(L, "Debug", hlua_txn_log_debug);
13642 hlua_class_function(L, "Info", hlua_txn_log_info);
13643 hlua_class_function(L, "Warning", hlua_txn_log_warning);
13644 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010013645
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013646 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010013647
13648 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013649 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013650
13651 /*
13652 *
Christopher Faulet700d9e82020-01-31 12:21:52 +010013653 * Register class reply
13654 *
13655 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013656 lua_newtable(L);
13657 lua_pushstring(L, "__index");
13658 lua_newtable(L);
13659 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
13660 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
13661 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
13662 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
13663 lua_settable(L, -3); /* Sets the __index entry. */
13664 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +010013665
13666
13667 /*
13668 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013669 * Register class Socket
13670 *
13671 */
13672
13673 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013674 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013675
Ilya Shipitsind4259502020-04-08 01:07:56 +050013676 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013677 lua_pushstring(L, "__index");
13678 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013679
Baptiste Assmann84bb4932015-03-02 21:40:06 +010013680#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013681 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +010013682#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013683 hlua_class_function(L, "connect", hlua_socket_connect);
13684 hlua_class_function(L, "send", hlua_socket_send);
13685 hlua_class_function(L, "receive", hlua_socket_receive);
13686 hlua_class_function(L, "close", hlua_socket_close);
13687 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
13688 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
13689 hlua_class_function(L, "setoption", hlua_socket_setoption);
13690 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013691
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013692 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013693
13694 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013695 lua_pushstring(L, "__gc");
13696 lua_pushcclosure(L, hlua_socket_gc, 0);
13697 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013698
13699 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010013700 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013701
Thierry Fournieraafc7772020-12-04 11:47:47 +010013702 lua_atpanic(L, hlua_panic_safe);
13703
13704 return L;
13705}
13706
13707void hlua_init(void) {
13708 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010013709 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +010013710#ifdef USE_OPENSSL
13711 struct srv_kw *kw;
13712 int tmp_error;
13713 char *error;
13714 char *args[] = { /* SSL client configuration. */
13715 "ssl",
13716 "verify",
13717 "none",
13718 NULL
13719 };
13720#endif
13721
13722 /* Init post init function list head */
13723 for (i = 0; i < MAX_THREADS + 1; i++)
13724 LIST_INIT(&hlua_init_functions[i]);
13725
13726 /* Init state for common/shared lua parts */
13727 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020013728 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010013729 hlua_states[0] = hlua_init_state(0);
13730
13731 /* Init state 1 for thread 0. We have at least one thread. */
13732 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020013733 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010013734 hlua_states[1] = hlua_init_state(1);
13735
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013736 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +020013737 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010013738 if (!socket_proxy) {
13739 fprintf(stderr, "Lua init: %s\n", errmsg);
13740 exit(1);
13741 }
13742 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013743
13744 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013745 socket_tcp = new_server(socket_proxy);
13746 if (!socket_tcp) {
13747 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
13748 exit(1);
13749 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013750
13751#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013752 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013753 socket_ssl = new_server(socket_proxy);
13754 if (!socket_ssl) {
13755 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
13756 exit(1);
13757 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013758
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013759 socket_ssl->use_ssl = 1;
13760 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013761
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000013762 for (i = 0; args[i] != NULL; i++) {
13763 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013764 /*
13765 *
13766 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080013767 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013768 * features like client certificates and ssl_verify.
13769 *
13770 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010013771 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013772 if (tmp_error != 0) {
13773 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
13774 abort(); /* This must be never arrives because the command line
13775 not editable by the user. */
13776 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000013777 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013778 }
13779 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010013780#endif
Thierry Fournier75933d42016-01-21 09:30:18 +010013781
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010013782}
Willy Tarreaubb57d942016-12-21 19:04:56 +010013783
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020013784static void hlua_deinit()
13785{
Willy Tarreau186f3762020-12-04 11:48:12 +010013786 int thr;
Christopher Faulet69c581a2021-05-31 08:54:04 +020013787 struct hlua_reg_filter *reg_flt, *reg_flt_bck;
13788
13789 list_for_each_entry_safe(reg_flt, reg_flt_bck, &referenced_filters, l)
13790 release_hlua_reg_filter(reg_flt);
Willy Tarreau186f3762020-12-04 11:48:12 +010013791
13792 for (thr = 0; thr < MAX_THREADS+1; thr++) {
13793 if (hlua_states[thr])
13794 lua_close(hlua_states[thr]);
13795 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +010013796
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020013797 srv_drop(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +010013798
Willy Tarreau0f143af2021-03-05 10:41:48 +010013799#ifdef USE_OPENSSL
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020013800 srv_drop(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +010013801#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010013802
13803 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020013804}
13805
13806REGISTER_POST_DEINIT(hlua_deinit);
13807
Willy Tarreau80713382018-11-26 10:19:54 +010013808static void hlua_register_build_options(void)
13809{
Willy Tarreaubb57d942016-12-21 19:04:56 +010013810 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +010013811
Willy Tarreaubb57d942016-12-21 19:04:56 +010013812 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
13813 hap_register_build_opts(ptr, 1);
13814}
Willy Tarreau80713382018-11-26 10:19:54 +010013815
13816INITCALL0(STG_REGISTER, hlua_register_build_options);