blob: 7704d17aff6273f184432ff242ed4a35d78140ce [file] [log] [blame]
Thierry Fourniere726b142016-02-11 17:57:57 +01001/*
2 * Lua unsafe core engine
3 *
4 * Copyright 2015-2016 Thierry Fournier <tfournier@arpalert.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Bertrand Jacquinf4c12d42021-01-21 21:14:07 +000013#define _GNU_SOURCE
14
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +010015#include <ctype.h>
Thierry FOURNIERbabae282015-09-17 11:36:37 +020016#include <setjmp.h>
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +010017
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010018#include <lauxlib.h>
19#include <lua.h>
20#include <lualib.h>
21
Thierry FOURNIER463119c2015-03-10 00:35:36 +010022#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503
23#error "Requires Lua 5.3 or later."
Cyril Bontédc0306e2015-03-02 00:08:40 +010024#endif
25
Willy Tarreau8d2b7772020-05-27 10:58:19 +020026#include <import/ebpttree.h>
Thierry FOURNIER380d0932015-01-23 14:27:52 +010027
Willy Tarreaub2551052020-06-09 09:07:15 +020028#include <haproxy/api.h>
29#include <haproxy/applet.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020030#include <haproxy/arg.h>
Christopher Fauletd25d9262020-08-06 11:04:46 +020031#include <haproxy/auth.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020032#include <haproxy/cfgparse.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020033#include <haproxy/channel.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020034#include <haproxy/cli.h>
Willy Tarreau55542642021-10-08 09:33:24 +020035#include <haproxy/clock.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020036#include <haproxy/connection.h>
Christopher Faulet69c581a2021-05-31 08:54:04 +020037#include <haproxy/filters.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020038#include <haproxy/h1.h>
Willy Tarreau86416052020-06-04 09:20:54 +020039#include <haproxy/hlua.h>
Willy Tarreau8c794002020-06-04 10:05:25 +020040#include <haproxy/hlua_fcn.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020041#include <haproxy/http_ana.h>
William Lallemand3956c4e2021-09-21 16:25:15 +020042#include <haproxy/http_client.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020043#include <haproxy/http_fetch.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020044#include <haproxy/http_htx.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020045#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020046#include <haproxy/log.h>
Willy Tarreau2cd58092020-06-04 15:10:43 +020047#include <haproxy/map.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020048#include <haproxy/obj_type.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020049#include <haproxy/pattern.h>
Willy Tarreau469509b2020-06-04 15:13:30 +020050#include <haproxy/payload.h>
Willy Tarreau3d6ee402021-05-08 20:28:07 +020051#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020052#include <haproxy/regex.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020053#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020054#include <haproxy/sc_strm.h>
Willy Tarreau198e92a2021-03-05 10:23:32 +010055#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +020056#include <haproxy/session.h>
William Lallemand30fcca12022-03-30 12:03:12 +020057#include <haproxy/ssl_ckch.h>
58#include <haproxy/ssl_sock.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020059#include <haproxy/stats-t.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020060#include <haproxy/stconn.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020061#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020062#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020063#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020064#include <haproxy/thread.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020065#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020066#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020067#include <haproxy/xref.h>
68
Thierry FOURNIER380d0932015-01-23 14:27:52 +010069
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010070/* Lua uses longjmp to perform yield or throwing errors. This
71 * macro is used only for identifying the function that can
72 * not return because a longjmp is executed.
73 * __LJMP marks a prototype of hlua file that can use longjmp.
74 * WILL_LJMP() marks an lua function that will use longjmp.
75 * MAY_LJMP() marks an lua function that may use longjmp.
76 */
77#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020078#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010079#define MAY_LJMP(func) func
80
Thierry FOURNIERbabae282015-09-17 11:36:37 +020081/* This couple of function executes securely some Lua calls outside of
82 * the lua runtime environment. Each Lua call can return a longjmp
83 * if it encounter a memory error.
84 *
85 * Lua documentation extract:
86 *
87 * If an error happens outside any protected environment, Lua calls
88 * a panic function (see lua_atpanic) and then calls abort, thus
89 * exiting the host application. Your panic function can avoid this
90 * exit by never returning (e.g., doing a long jump to your own
91 * recovery point outside Lua).
92 *
93 * The panic function runs as if it were a message handler (see
Willy Tarreau3dfb7da2022-03-02 22:33:39 +010094 * #2.3); in particular, the error message is at the top of the
Thierry FOURNIERbabae282015-09-17 11:36:37 +020095 * stack. However, there is no guarantee about stack space. To push
96 * anything on the stack, the panic function must first check the
Willy Tarreau3dfb7da2022-03-02 22:33:39 +010097 * available space (see #4.2).
Thierry FOURNIERbabae282015-09-17 11:36:37 +020098 *
99 * We must check all the Lua entry point. This includes:
100 * - The include/proto/hlua.h exported functions
101 * - the task wrapper function
102 * - The action wrapper function
103 * - The converters wrapper function
104 * - The sample-fetch wrapper functions
105 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500106 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800107 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200108 *
109 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
110 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
111 * because they must be exists in the program stack when the longjmp
112 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200113 *
114 * Note that the Lua processing is not really thread safe. It provides
115 * heavy system which consists to add our own lock function in the Lua
116 * code and recompile the library. This system will probably not accepted
117 * by maintainers of various distribs.
118 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500119 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200120 * quick looking on the Lua sources displays a lua_lock() a the start
121 * of function and a lua_unlock() at the end of the function. So I
122 * conclude that the Lua thread safe mode just perform a mutex around
123 * all execution. So I prefer to do this in the HAProxy code, it will be
124 * easier for distro maintainers.
125 *
126 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
127 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
128 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200129 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100130__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200131THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200132static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau6a510902021-07-14 19:41:25 +0200133static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); return 0; }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200134
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100135/* This is the chained list of struct hlua_function referenced
136 * for haproxy action, sample-fetches, converters, cli and
137 * applet bindings. It is used for a post-initialisation control.
138 */
139static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
140
Thierry Fournierc7492592020-11-28 23:57:24 +0100141/* This variable is used only during initialization to identify the Lua state
142 * currently being initialized. 0 is the common lua state, 1 to n are the Lua
143 * states dedicated to each thread (in this case hlua_state_id==tid+1).
144 */
145static int hlua_state_id;
146
Thierry Fournier59f11be2020-11-29 00:37:41 +0100147/* This is a NULL-terminated list of lua file which are referenced to load per thread */
Thierry Fournierae6b5682022-09-19 09:04:16 +0200148static char ***per_thread_load = NULL;
Thierry Fournier59f11be2020-11-29 00:37:41 +0100149
150lua_State *hlua_init_state(int thread_id);
151
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200152/* This function takes the Lua global lock. Keep this function's visibility
153 * global so that it can appear in stack dumps and performance profiles!
154 */
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100155static inline void lua_take_global_lock()
Willy Tarreau1e7bef12021-08-20 15:47:25 +0200156{
157 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
158}
159
160static inline void lua_drop_global_lock()
161{
162 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
163}
164
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100165/* lua lock helpers: only lock when required */
166static inline void hlua_lock(struct hlua *hlua)
167{
168 if (hlua->state_id == 0)
169 lua_take_global_lock();
170}
171static inline void hlua_unlock(struct hlua *hlua)
172{
173 if (hlua->state_id == 0)
174 lua_drop_global_lock();
175}
176
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100177#define SET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200178 ({ \
179 int ret; \
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100180 hlua_lock(__HLUA); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200181 if (setjmp(safe_ljmp_env) != 0) { \
182 lua_atpanic(__L, hlua_panic_safe); \
183 ret = 0; \
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100184 hlua_unlock(__HLUA); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200185 } else { \
186 lua_atpanic(__L, hlua_panic_ljmp); \
187 ret = 1; \
188 } \
189 ret; \
190 })
191
192/* If we are the last function catching Lua errors, we
193 * must reset the panic function.
194 */
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100195#define RESET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200196 do { \
197 lua_atpanic(__L, hlua_panic_safe); \
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +0100198 hlua_unlock(__HLUA); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200199 } while(0)
200
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100201#define SET_SAFE_LJMP(__HLUA) \
202 SET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
203
204#define RESET_SAFE_LJMP(__HLUA) \
205 RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
206
207#define SET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100208 SET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100209
210#define RESET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100211 RESET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100212
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200213/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200214#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100215/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200216#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200217/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100218#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100219#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200220
Thierry Fournierafc63e22020-11-28 17:06:51 +0100221/* The main Lua execution context. The 0 index is the
222 * common state shared by all threads.
223 */
Willy Tarreau186f3762020-12-04 11:48:12 +0100224static lua_State *hlua_states[MAX_THREADS + 1];
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100225
Christopher Fauletc404f112020-02-26 15:03:09 +0100226#define HLUA_FLT_CB_FINAL 0x00000001
227#define HLUA_FLT_CB_RETVAL 0x00000002
228#define HLUA_FLT_CB_ARG_CHN 0x00000004
229#define HLUA_FLT_CB_ARG_HTTP_MSG 0x00000008
230
Christopher Faulet9f55a502020-02-25 15:21:02 +0100231#define HLUA_FLT_CTX_FL_PAYLOAD 0x00000001
232
Christopher Faulet69c581a2021-05-31 08:54:04 +0200233struct hlua_reg_filter {
234 char *name;
235 int flt_ref[MAX_THREADS + 1];
236 int fun_ref[MAX_THREADS + 1];
237 struct list l;
238};
239
240struct hlua_flt_config {
241 struct hlua_reg_filter *reg;
242 int ref[MAX_THREADS + 1];
243 char **args;
244};
245
246struct hlua_flt_ctx {
247 int ref; /* ref to the filter lua object */
248 struct hlua *hlua[2]; /* lua runtime context (0: request, 1: response) */
249 unsigned int cur_off[2]; /* current offset (0: request, 1: response) */
250 unsigned int cur_len[2]; /* current forwardable length (0: request, 1: response) */
251 unsigned int flags; /* HLUA_FLT_CTX_FL_* */
252};
253
Willy Tarreau5321da92022-05-06 11:57:34 +0200254/* appctx context used by the cosockets */
255struct hlua_csk_ctx {
256 int connected;
257 struct xref xref; /* cross reference with the Lua object owner. */
258 struct list wake_on_read;
259 struct list wake_on_write;
260 struct appctx *appctx;
261 int die;
262};
263
Willy Tarreaue23f33b2022-05-06 14:07:13 +0200264/* appctx context used by TCP services */
265struct hlua_tcp_ctx {
266 struct hlua *hlua;
267 int flags;
268 struct task *task;
269};
270
Willy Tarreauaa229cc2022-05-06 14:26:10 +0200271/* appctx context used by HTTP services */
272struct hlua_http_ctx {
273 struct hlua *hlua;
274 int left_bytes; /* The max amount of bytes that we can read. */
275 int flags;
276 int status;
277 const char *reason;
278 struct task *task;
279};
280
Willy Tarreaubcda5f62022-05-03 18:13:39 +0200281/* used by registered CLI keywords */
282struct hlua_cli_ctx {
283 struct hlua *hlua;
284 struct task *task;
285 struct hlua_function *fcn;
286};
287
Christopher Faulet69c581a2021-05-31 08:54:04 +0200288DECLARE_STATIC_POOL(pool_head_hlua_flt_ctx, "hlua_flt_ctx", sizeof(struct hlua_flt_ctx));
289
Christopher Faulet9f55a502020-02-25 15:21:02 +0100290static int hlua_filter_from_payload(struct filter *filter);
291
Christopher Faulet69c581a2021-05-31 08:54:04 +0200292/* This is the chained list of struct hlua_flt referenced
293 * for haproxy filters. It is used for a post-initialisation control.
294 */
295static struct list referenced_filters = LIST_HEAD_INIT(referenced_filters);
296
297
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100298/* This is the memory pool containing struct lua for applets
299 * (including cli).
300 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100301DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100302
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100303/* Used for Socket connection. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +0100304static struct proxy *socket_proxy;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100305static struct server *socket_tcp;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100306#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100307static struct server *socket_ssl;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100308#endif
309
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100310/* List head of the function called at the initialisation time. */
Thierry Fournierc7492592020-11-28 23:57:24 +0100311struct list hlua_init_functions[MAX_THREADS + 1];
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100312
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100313/* The following variables contains the reference of the different
314 * Lua classes. These references are useful for identify metadata
315 * associated with an object.
316 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100317static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100318static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100319static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100320static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100321static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100322static int class_http_ref;
Christopher Fauletdf97ac42020-02-26 16:57:19 +0100323static int class_http_msg_ref;
William Lallemand3956c4e2021-09-21 16:25:15 +0200324static int class_httpclient_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200325static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200326static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200327static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100328static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100329
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100330/* Global Lua execution timeout. By default Lua, execution linked
Willy Tarreau87b09662015-04-03 00:22:06 +0200331 * with stream (actions, sample-fetches and converters) have a
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100332 * short timeout. Lua linked with tasks doesn't have a timeout
333 * because a task may remain alive during all the haproxy execution.
334 */
335static unsigned int hlua_timeout_session = 4000; /* session timeout. */
336static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200337static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100338
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100339/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
340 * it is used for preventing infinite loops.
341 *
342 * I test the scheer with an infinite loop containing one incrementation
343 * and one test. I run this loop between 10 seconds, I raise a ceil of
344 * 710M loops from one interrupt each 9000 instructions, so I fix the value
345 * to one interrupt each 10 000 instructions.
346 *
347 * configured | Number of
348 * instructions | loops executed
349 * between two | in milions
350 * forced yields |
351 * ---------------+---------------
352 * 10 | 160
353 * 500 | 670
354 * 1000 | 680
355 * 5000 | 700
356 * 7000 | 700
357 * 8000 | 700
358 * 9000 | 710 <- ceil
359 * 10000 | 710
360 * 100000 | 710
361 * 1000000 | 710
362 *
363 */
364static unsigned int hlua_nb_instruction = 10000;
365
Willy Tarreaucdb53462020-12-02 12:12:00 +0100366/* Descriptor for the memory allocation state. The limit is pre-initialised to
367 * 0 until it is replaced by "tune.lua.maxmem" during the config parsing, or it
368 * is replaced with ~0 during post_init after everything was loaded. This way
369 * it is guaranteed that if limit is ~0 the boot is complete and that if it's
370 * zero it's not yet limited and proper accounting is required.
Willy Tarreau32f61e22015-03-18 17:54:59 +0100371 */
372struct hlua_mem_allocator {
373 size_t allocated;
374 size_t limit;
375};
376
Willy Tarreaucdb53462020-12-02 12:12:00 +0100377static struct hlua_mem_allocator hlua_global_allocator THREAD_ALIGNED(64);
Willy Tarreau32f61e22015-03-18 17:54:59 +0100378
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100379/* These functions converts types between HAProxy internal args or
380 * sample and LUA types. Another function permits to check if the
381 * LUA stack contains arguments according with an required ARG_T
382 * format.
383 */
384static int hlua_arg2lua(lua_State *L, const struct arg *arg);
385static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100386__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100387 uint64_t mask, struct proxy *p);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100388static int hlua_smp2lua(lua_State *L, struct sample *smp);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100389static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100390static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
391
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100392__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200393
Thierry Fournier59f11be2020-11-29 00:37:41 +0100394struct prepend_path {
395 struct list l;
396 char *type;
397 char *path;
398};
399
400static struct list prepend_path_list = LIST_HEAD_INIT(prepend_path_list);
401
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200402#define SEND_ERR(__be, __fmt, __args...) \
403 do { \
404 send_log(__be, LOG_ERR, __fmt, ## __args); \
405 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100406 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200407 } while (0)
408
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100409static inline struct hlua_function *new_hlua_function()
410{
411 struct hlua_function *fcn;
Thierry Fournierc7492592020-11-28 23:57:24 +0100412 int i;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100413
414 fcn = calloc(1, sizeof(*fcn));
415 if (!fcn)
416 return NULL;
Willy Tarreau2b718102021-04-21 07:32:39 +0200417 LIST_APPEND(&referenced_functions, &fcn->l);
Thierry Fournierc7492592020-11-28 23:57:24 +0100418 for (i = 0; i < MAX_THREADS + 1; i++)
419 fcn->function_ref[i] = -1;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100420 return fcn;
421}
422
Christopher Fauletdda44442021-04-12 14:05:43 +0200423static inline void release_hlua_function(struct hlua_function *fcn)
424{
425 if (!fcn)
426 return;
427 if (fcn->name)
428 ha_free(&fcn->name);
Willy Tarreau2b718102021-04-21 07:32:39 +0200429 LIST_DELETE(&fcn->l);
Christopher Fauletdda44442021-04-12 14:05:43 +0200430 ha_free(&fcn);
431}
432
Thierry Fournierc7492592020-11-28 23:57:24 +0100433/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
434static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
435{
436 if (fcn->function_ref[0] == -1)
437 return tid + 1;
438 return 0;
439}
440
Christopher Faulet69c581a2021-05-31 08:54:04 +0200441/* Create a new registered filter. Only its name is filled */
442static inline struct hlua_reg_filter *new_hlua_reg_filter(const char *name)
443{
444 struct hlua_reg_filter *reg_flt;
445 int i;
446
447 reg_flt = calloc(1, sizeof(*reg_flt));
448 if (!reg_flt)
449 return NULL;
450 reg_flt->name = strdup(name);
451 if (!reg_flt->name) {
452 free(reg_flt);
453 return NULL;
454 }
455 LIST_APPEND(&referenced_filters, &reg_flt->l);
456 for (i = 0; i < MAX_THREADS + 1; i++) {
457 reg_flt->flt_ref[i] = -1;
458 reg_flt->fun_ref[i] = -1;
459 }
460 return reg_flt;
461}
462
463/* Release a registered filter */
464static inline void release_hlua_reg_filter(struct hlua_reg_filter *reg_flt)
465{
466 if (!reg_flt)
467 return;
468 if (reg_flt->name)
469 ha_free(&reg_flt->name);
470 LIST_DELETE(&reg_flt->l);
471 ha_free(&reg_flt);
472}
473
474/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
475static inline int reg_flt_to_stack_id(struct hlua_reg_filter *reg_flt)
476{
477 if (reg_flt->fun_ref[0] == -1)
478 return tid + 1;
479 return 0;
480}
481
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100482/* Used to check an Lua function type in the stack. It creates and
483 * returns a reference of the function. This function throws an
Aurelien DARRAGONf8f8a2b2023-03-02 17:50:49 +0100484 * error if the argument is not a "function".
485 * When no longer used, the ref must be released with hlua_unref()
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100486 */
Aurelien DARRAGON9ee0d042023-03-20 18:36:08 +0100487__LJMP int hlua_checkfunction(lua_State *L, int argno)
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100488{
489 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100490 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100491 WILL_LJMP(luaL_argerror(L, argno, msg));
492 }
493 lua_pushvalue(L, argno);
494 return luaL_ref(L, LUA_REGISTRYINDEX);
495}
496
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100497/* Used to check an Lua table type in the stack. It creates and
498 * returns a reference of the table. This function throws an
Aurelien DARRAGONf8f8a2b2023-03-02 17:50:49 +0100499 * error if the argument is not a "table".
500 * When no longer used, the ref must be released with hlua_unref()
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100501 */
Aurelien DARRAGON9ee0d042023-03-20 18:36:08 +0100502__LJMP int hlua_checktable(lua_State *L, int argno)
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100503{
504 if (!lua_istable(L, argno)) {
505 const char *msg = lua_pushfstring(L, "table expected, got %s", luaL_typename(L, argno));
506 WILL_LJMP(luaL_argerror(L, argno, msg));
507 }
508 lua_pushvalue(L, argno);
509 return luaL_ref(L, LUA_REGISTRYINDEX);
510}
511
Aurelien DARRAGONf8f8a2b2023-03-02 17:50:49 +0100512/* Get a reference to the object that is at the top of the stack
513 * The referenced object will be popped from the stack
514 *
515 * The function returns the reference to the object which must
516 * be cleared using hlua_unref() when no longer used
517 */
518__LJMP int hlua_ref(lua_State *L)
519{
520 return MAY_LJMP(luaL_ref(L, LUA_REGISTRYINDEX));
521}
522
523/* Pushes a reference previously created using luaL_ref(L, LUA_REGISTRYINDEX)
524 * on <L> stack
525 * (ie: hlua_checkfunction(), hlua_checktable() or hlua_ref())
526 *
527 * When the reference is no longer used, it should be released by calling
528 * hlua_unref()
529 *
530 * <L> can be from any co-routine as long as it belongs to the same lua
531 * parent state that the one used to get the reference.
532 */
533void hlua_pushref(lua_State *L, int ref)
534{
535 lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
536}
537
538/* Releases a reference previously created using luaL_ref(L, LUA_REGISTRYINDEX)
539 * (ie: hlua_checkfunction(), hlua_checktable() or hlua_ref())
540 *
541 * This will allow the reference to be reused and the referred object
542 * to be garbage collected.
543 *
544 * <L> can be from any co-routine as long as it belongs to the same lua
545 * parent state that the one used to get the reference.
546 */
547void hlua_unref(lua_State *L, int ref)
548{
549 luaL_unref(L, LUA_REGISTRYINDEX, ref);
550}
551
Christopher Fauletd09cc512021-03-24 14:48:45 +0100552__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200553{
554 lua_Debug ar;
555 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200556 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200557
558 while (lua_getstack(L, level++, &ar)) {
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200559 /* Fill fields:
560 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
561 * 'l': fills in the field currentline;
562 * 'n': fills in the field name and namewhat;
563 * 't': fills in the field istailcall;
564 */
565 lua_getinfo(L, "Slnt", &ar);
566
Willy Tarreau5c143402022-06-19 17:35:53 +0200567 /* skip these empty entries, usually they come from deep C functions */
568 if (ar.currentline < 0 && *ar.what == 'C' && !*ar.namewhat && !ar.name)
569 continue;
570
571 /* Add separator */
572 if (b_data(msg))
573 chunk_appendf(msg, "%s", sep);
574
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200575 /* Append code localisation */
576 if (ar.currentline > 0)
Christopher Fauletd09cc512021-03-24 14:48:45 +0100577 chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200578 else
Christopher Fauletd09cc512021-03-24 14:48:45 +0100579 chunk_appendf(msg, "%s: ", ar.short_src);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200580
581 /*
582 * Get function name
583 *
584 * if namewhat is no empty, name is defined.
585 * what contains "Lua" for Lua function, "C" for C function,
586 * or "main" for main code.
587 */
588 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100589 chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200590
591 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100592 chunk_appendf(msg, "in main chunk");
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200593
594 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100595 chunk_appendf(msg, "in function line %d", ar.linedefined);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200596
597 else /* nothing left... */
598 chunk_appendf(msg, "?");
599
600
601 /* Display tailed call */
602 if (ar.istailcall)
603 chunk_appendf(msg, " ...");
604 }
605
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200606 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200607}
608
609
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100610/* This function check the number of arguments available in the
611 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500612 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100613 */
614__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
615{
616 if (lua_gettop(L) == nb)
617 return;
618 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
619}
620
Mark Lakes22154b42018-01-29 14:38:40 -0800621/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100622 * and the line number where the error is encountered.
623 */
624static int hlua_pusherror(lua_State *L, const char *fmt, ...)
625{
626 va_list argp;
627 va_start(argp, fmt);
628 luaL_where(L, 1);
629 lua_pushvfstring(L, fmt, argp);
630 va_end(argp);
631 lua_concat(L, 2);
632 return 1;
633}
634
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100635/* This functions is used with sample fetch and converters. It
636 * converts the HAProxy configuration argument in a lua stack
637 * values.
638 *
639 * It takes an array of "arg", and each entry of the array is
640 * converted and pushed in the LUA stack.
641 */
642static int hlua_arg2lua(lua_State *L, const struct arg *arg)
643{
644 switch (arg->type) {
645 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100646 case ARGT_TIME:
647 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100648 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100649 break;
650
651 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200652 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100653 break;
654
655 case ARGT_IPV4:
656 case ARGT_IPV6:
657 case ARGT_MSK4:
658 case ARGT_MSK6:
659 case ARGT_FE:
660 case ARGT_BE:
661 case ARGT_TAB:
662 case ARGT_SRV:
663 case ARGT_USR:
664 case ARGT_MAP:
665 default:
666 lua_pushnil(L);
667 break;
668 }
669 return 1;
670}
671
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500672/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100673 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500674 * with sample fetch wrappers. The input arguments are given to the
675 * lua wrapper and converted as arg list by the function.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100676 */
677static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
678{
679 switch (lua_type(L, ud)) {
680
681 case LUA_TNUMBER:
682 case LUA_TBOOLEAN:
683 arg->type = ARGT_SINT;
684 arg->data.sint = lua_tointeger(L, ud);
685 break;
686
687 case LUA_TSTRING:
688 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200689 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200690 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200691 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200692 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100693 break;
694
695 case LUA_TUSERDATA:
696 case LUA_TNIL:
697 case LUA_TTABLE:
698 case LUA_TFUNCTION:
699 case LUA_TTHREAD:
700 case LUA_TLIGHTUSERDATA:
701 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200702 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100703 break;
704 }
705 return 1;
706}
707
708/* the following functions are used to convert a struct sample
709 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500710 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100711 */
Willy Tarreau5eadada2015-03-10 17:28:54 +0100712static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100713{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200714 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100715 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100716 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200717 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100718 break;
719
720 case SMP_T_BIN:
721 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200722 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100723 break;
724
725 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200726 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100727 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
728 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
729 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
730 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
731 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
732 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
733 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
734 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
735 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200736 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100737 break;
738 default:
739 lua_pushnil(L);
740 break;
741 }
742 break;
743
744 case SMP_T_IPV4:
745 case SMP_T_IPV6:
746 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200747 if (sample_casts[smp->data.type][SMP_T_STR] &&
748 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200749 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100750 else
751 lua_pushnil(L);
752 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100753 default:
754 lua_pushnil(L);
755 break;
756 }
757 return 1;
758}
759
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100760/* the following functions are used to convert a struct sample
761 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500762 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100763 */
764static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
765{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200766 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100767
768 case SMP_T_BIN:
769 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200770 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100771 break;
772
773 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200774 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100775 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
776 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
777 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
778 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
779 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
780 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
781 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
782 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
783 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200784 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100785 break;
786 default:
787 lua_pushstring(L, "");
788 break;
789 }
790 break;
791
792 case SMP_T_SINT:
793 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100794 case SMP_T_IPV4:
795 case SMP_T_IPV6:
796 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200797 if (sample_casts[smp->data.type][SMP_T_STR] &&
798 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200799 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100800 else
801 lua_pushstring(L, "");
802 break;
803 default:
804 lua_pushstring(L, "");
805 break;
806 }
807 return 1;
808}
809
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100810/* the following functions are used to convert an Lua type in a
811 * struct sample. This is useful to provide data from a converter
812 * to the LUA code.
813 */
814static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
815{
816 switch (lua_type(L, ud)) {
817
818 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200819 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200820 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100821 break;
822
823
824 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200825 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200826 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100827 break;
828
829 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200830 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100831 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200832 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200833 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200834 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200835 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100836 break;
837
838 case LUA_TUSERDATA:
839 case LUA_TNIL:
840 case LUA_TTABLE:
841 case LUA_TFUNCTION:
842 case LUA_TTHREAD:
843 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +0200844 case LUA_TNONE:
845 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200846 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200847 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100848 break;
849 }
850 return 1;
851}
852
Ilya Shipitsind4259502020-04-08 01:07:56 +0500853/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800854 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100855 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100856 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500857 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Willy Tarreauee0d7272021-07-16 10:26:56 +0200858 * entries and that there is at least one stop at the last position.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100859 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100860__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100861 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100862{
863 int min_arg;
Willy Tarreauee0d7272021-07-16 10:26:56 +0200864 int idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100865 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +0200866 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200867 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200868 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200869 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100870
871 idx = 0;
872 min_arg = ARGM(mask);
873 mask >>= ARGM_BITS;
874
875 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200876 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100877
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100878 /* Check for mandatory arguments. */
879 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100880 if (idx < min_arg) {
881
882 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200883 if (idx > 0) {
884 msg = "Mandatory argument expected";
885 goto error;
886 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100887
888 /* If first argument have a certain type, some default values
889 * may be used. See the function smp_resolve_args().
890 */
891 switch (mask & ARGT_MASK) {
892
893 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200894 if (!(p->cap & PR_CAP_FE)) {
895 msg = "Mandatory argument expected";
896 goto error;
897 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100898 argp[idx].data.prx = p;
899 argp[idx].type = ARGT_FE;
900 argp[idx+1].type = ARGT_STOP;
901 break;
902
903 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200904 if (!(p->cap & PR_CAP_BE)) {
905 msg = "Mandatory argument expected";
906 goto error;
907 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100908 argp[idx].data.prx = p;
909 argp[idx].type = ARGT_BE;
910 argp[idx+1].type = ARGT_STOP;
911 break;
912
913 case ARGT_TAB:
Olivier Houchard14f62682022-09-13 00:35:53 +0200914 if (!p->table) {
915 msg = "Mandatory argument expected";
916 goto error;
917 }
918 argp[idx].data.t = p->table;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100919 argp[idx].type = ARGT_TAB;
920 argp[idx+1].type = ARGT_STOP;
921 break;
922
923 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200924 msg = "Mandatory argument expected";
925 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100926 break;
927 }
928 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200929 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100930 }
931
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500932 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100933 if ((mask & ARGT_MASK) == ARGT_STOP &&
934 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200935 msg = "Last argument expected";
936 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100937 }
938
939 if ((mask & ARGT_MASK) == ARGT_STOP &&
940 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200941 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100942 }
943
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200944 /* Convert some argument types. All string in argp[] are for not
945 * duplicated yet.
946 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100947 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100948 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200949 if (argp[idx].type != ARGT_SINT) {
950 msg = "integer expected";
951 goto error;
952 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100953 argp[idx].type = ARGT_SINT;
954 break;
955
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100956 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200957 if (argp[idx].type != ARGT_SINT) {
958 msg = "integer expected";
959 goto error;
960 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200961 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100962 break;
963
964 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200965 if (argp[idx].type != ARGT_SINT) {
966 msg = "integer expected";
967 goto error;
968 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200969 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100970 break;
971
972 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200973 if (argp[idx].type != ARGT_STR) {
974 msg = "string expected";
975 goto error;
976 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200977 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200978 if (!argp[idx].data.prx) {
979 msg = "frontend doesn't exist";
980 goto error;
981 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100982 argp[idx].type = ARGT_FE;
983 break;
984
985 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200986 if (argp[idx].type != ARGT_STR) {
987 msg = "string expected";
988 goto error;
989 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200990 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200991 if (!argp[idx].data.prx) {
992 msg = "backend doesn't exist";
993 goto error;
994 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100995 argp[idx].type = ARGT_BE;
996 break;
997
998 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200999 if (argp[idx].type != ARGT_STR) {
1000 msg = "string expected";
1001 goto error;
1002 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001003 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001004 if (!argp[idx].data.t) {
1005 msg = "table doesn't exist";
1006 goto error;
1007 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001008 argp[idx].type = ARGT_TAB;
1009 break;
1010
1011 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001012 if (argp[idx].type != ARGT_STR) {
1013 msg = "string expected";
1014 goto error;
1015 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001016 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001017 if (sname) {
1018 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001019 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +02001020 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001021 if (!px) {
1022 msg = "backend doesn't exist";
1023 goto error;
1024 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001025 }
1026 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +02001027 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001028 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001029 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001030 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001031 if (!argp[idx].data.srv) {
1032 msg = "server doesn't exist";
1033 goto error;
1034 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001035 argp[idx].type = ARGT_SRV;
1036 break;
1037
1038 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001039 if (argp[idx].type != ARGT_STR) {
1040 msg = "string expected";
1041 goto error;
1042 }
1043 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
1044 msg = "invalid IPv4 address";
1045 goto error;
1046 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001047 argp[idx].type = ARGT_IPV4;
1048 break;
1049
1050 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +02001051 if (argp[idx].type == ARGT_SINT)
1052 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
1053 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001054 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
1055 msg = "invalid IPv4 mask";
1056 goto error;
1057 }
1058 }
1059 else {
1060 msg = "integer or string expected";
1061 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +02001062 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001063 argp[idx].type = ARGT_MSK4;
1064 break;
1065
1066 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001067 if (argp[idx].type != ARGT_STR) {
1068 msg = "string expected";
1069 goto error;
1070 }
1071 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
1072 msg = "invalid IPv6 address";
1073 goto error;
1074 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001075 argp[idx].type = ARGT_IPV6;
1076 break;
1077
1078 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +02001079 if (argp[idx].type == ARGT_SINT)
1080 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
1081 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001082 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
1083 msg = "invalid IPv6 mask";
1084 goto error;
1085 }
1086 }
1087 else {
1088 msg = "integer or string expected";
1089 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +02001090 }
Tim Duesterhusb814da62018-01-25 16:24:50 +01001091 argp[idx].type = ARGT_MSK6;
1092 break;
1093
Christopher Fauletfd2e9062020-08-06 11:10:57 +02001094 case ARGT_REG:
1095 if (argp[idx].type != ARGT_STR) {
1096 msg = "string expected";
1097 goto error;
1098 }
1099 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
1100 if (!reg) {
1101 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
1102 argp[idx].data.str.area, err);
1103 free(err);
1104 goto error;
1105 }
1106 argp[idx].type = ARGT_REG;
1107 argp[idx].data.reg = reg;
1108 break;
1109
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +01001110 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001111 if (argp[idx].type != ARGT_STR) {
1112 msg = "string expected";
1113 goto error;
1114 }
1115 if (p->uri_auth && p->uri_auth->userlist &&
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001116 strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area) == 0)
Christopher Fauletd25d9262020-08-06 11:04:46 +02001117 ul = p->uri_auth->userlist;
1118 else
1119 ul = auth_find_userlist(argp[idx].data.str.area);
1120
1121 if (!ul) {
1122 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
1123 goto error;
1124 }
1125 argp[idx].type = ARGT_USR;
1126 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001127 break;
1128
1129 case ARGT_STR:
1130 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
1131 msg = "unable to duplicate string arg";
1132 goto error;
1133 }
1134 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001135 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001136
Christopher Fauletd25d9262020-08-06 11:04:46 +02001137 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001138 msg = "type not yet supported";
1139 goto error;
1140 break;
1141
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001142 }
1143
1144 /* Check for type of argument. */
1145 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001146 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
1147 arg_type_names[(mask & ARGT_MASK)],
1148 arg_type_names[argp[idx].type & ARGT_MASK]);
1149 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001150 }
1151
1152 /* Next argument. */
1153 mask >>= ARGT_BITS;
1154 idx++;
1155 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001156 return 0;
1157
1158 error:
Olivier Houchardca431612022-09-13 00:31:17 +02001159 argp[idx].type = ARGT_STOP;
Willy Tarreauee0d7272021-07-16 10:26:56 +02001160 free_args(argp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001161 WILL_LJMP(luaL_argerror(L, first + idx, msg));
1162 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001163}
1164
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001165/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001166 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001167 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001168 *
1169 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001170 * - hlua_sethlua : create the association between hlua context and lua_state.
1171 */
1172static inline struct hlua *hlua_gethlua(lua_State *L)
1173{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001174 struct hlua **hlua = lua_getextraspace(L);
1175 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001176}
1177static inline void hlua_sethlua(struct hlua *hlua)
1178{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001179 struct hlua **hlua_store = lua_getextraspace(hlua->T);
1180 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001181}
1182
Willy Tarreau0b7b6392022-06-19 17:39:33 +02001183/* Will return a non-NULL string indicating the Lua call trace if the caller
1184 * currently is executing from within a Lua function. One line per entry will
1185 * be emitted, and each extra line will be prefixed with <pfx>. If a current
1186 * Lua function is not detected, NULL is returned.
1187 */
1188const char *hlua_show_current_location(const char *pfx)
1189{
1190 lua_State *L;
1191 lua_Debug ar;
1192
1193 /* global or per-thread stack initializing ? */
1194 if (hlua_state_id != -1 && (L = hlua_states[hlua_state_id]) && lua_getstack(L, 0, &ar))
1195 return hlua_traceback(L, pfx);
1196
1197 /* per-thread stack running ? */
1198 if (hlua_states[tid + 1] && (L = hlua_states[tid + 1]) && lua_getstack(L, 0, &ar))
1199 return hlua_traceback(L, pfx);
1200
1201 /* global stack running ? */
1202 if (hlua_states[0] && (L = hlua_states[0]) && lua_getstack(L, 0, &ar))
1203 return hlua_traceback(L, pfx);
1204
1205 return NULL;
1206}
1207
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001208/* This function is used to send logs. It try to send on screen (stderr)
1209 * and on the default syslog server.
1210 */
1211static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
1212{
1213 struct tm tm;
1214 char *p;
1215
1216 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001217 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001218 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001219 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +02001220 /* Break the message if exceed the buffer size. */
1221 *(p-4) = ' ';
1222 *(p-3) = '.';
1223 *(p-2) = '.';
1224 *(p-1) = '.';
1225 break;
1226 }
Willy Tarreau90807112020-02-25 08:16:33 +01001227 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001228 *p = *msg;
1229 else
1230 *p = '.';
1231 }
1232 *p = '\0';
1233
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001234 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001235 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +02001236 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
1237 return;
1238
Willy Tarreaua678b432015-08-28 10:14:59 +02001239 get_localtime(date.tv_sec, &tm);
1240 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001241 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001242 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001243 fflush(stderr);
1244 }
1245}
1246
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001247/* This function just ensure that the yield will be always
1248 * returned with a timeout and permit to set some flags
1249 */
1250__LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001251 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001252{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001253 struct hlua *hlua;
1254
1255 /* Get hlua struct, or NULL if we execute from main lua state */
1256 hlua = hlua_gethlua(L);
1257 if (!hlua) {
1258 return;
1259 }
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001260
1261 /* Set the wake timeout. If timeout is required, we set
1262 * the expiration time.
1263 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001264 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001265
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +01001266 hlua->flags |= flags;
1267
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001268 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +02001269 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001270}
1271
Willy Tarreau87b09662015-04-03 00:22:06 +02001272/* This function initialises the Lua environment stored in the stream.
1273 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001274 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001275 *
1276 * This function is particular. it initialises a new Lua thread. If the
1277 * initialisation fails (example: out of memory error), the lua function
1278 * throws an error (longjmp).
1279 *
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001280 * In some case (at least one), this function can be called from safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001281 * environment, so we must not initialise it. While the support of
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001282 * threads appear, the safe environment set a lock to ensure only one
1283 * Lua execution at a time. If we initialize safe environment in another
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001284 * safe environment, we have a dead lock.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001285 *
1286 * set "already_safe" true if the context is initialized form safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001287 * Lua function.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001288 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001289 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001290 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001291 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001292 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001293 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001294int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already_safe)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001295{
1296 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001297 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001298 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001299 lua->wake_time = TICK_ETERNITY;
Thierry Fournier021d9862020-11-28 23:42:03 +01001300 lua->state_id = state_id;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001301 LIST_INIT(&lua->com);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001302 MT_LIST_INIT(&lua->hc_list);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001303 if (!already_safe) {
1304 if (!SET_SAFE_LJMP_PARENT(lua)) {
1305 lua->Tref = LUA_REFNIL;
1306 return 0;
1307 }
1308 }
Thierry Fournier021d9862020-11-28 23:42:03 +01001309 lua->T = lua_newthread(hlua_states[state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001310 if (!lua->T) {
1311 lua->Tref = LUA_REFNIL;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001312 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001313 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001314 return 0;
1315 }
1316 hlua_sethlua(lua);
Thierry Fournier021d9862020-11-28 23:42:03 +01001317 lua->Tref = luaL_ref(hlua_states[state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001318 lua->task = task;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001319 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001320 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001321 return 1;
1322}
1323
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001324/* kill all associated httpclient to this hlua task
1325 * We must take extra precautions as we're manipulating lua-exposed
1326 * objects without the main lua lock.
1327 */
William Lallemandbb581422022-10-20 10:57:28 +02001328static void hlua_httpclient_destroy_all(struct hlua *hlua)
1329{
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001330 struct hlua_httpclient *hlua_hc;
William Lallemandbb581422022-10-20 10:57:28 +02001331
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01001332 /* use thread-safe accessors for hc_list since GC cycle initiated by
1333 * another thread sharing the same main lua stack (lua coroutine)
1334 * could execute hlua_httpclient_gc() on the hlua->hc_list items
1335 * in parallel: Lua GC applies on the main stack, it is not limited to
1336 * a single coroutine stack, see Github issue #2037 for reference.
1337 * Remember, coroutines created using lua_newthread() are not meant to
1338 * be thread safe in Lua. (From lua co-author:
1339 * http://lua-users.org/lists/lua-l/2011-07/msg00072.html)
1340 *
1341 * This security measure is superfluous when 'lua-load-per-thread' is used
1342 * since in this case coroutines exclusively run on the same thread
1343 * (main stack is not shared between OS threads).
1344 */
1345 while ((hlua_hc = MT_LIST_POP(&hlua->hc_list, typeof(hlua_hc), by_hlua))) {
1346 httpclient_stop_and_destroy(hlua_hc->hc);
William Lallemandbb581422022-10-20 10:57:28 +02001347 hlua_hc->hc = NULL;
William Lallemandbb581422022-10-20 10:57:28 +02001348 }
1349}
1350
1351
Willy Tarreau87b09662015-04-03 00:22:06 +02001352/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001353 * is destroyed. The destroy also the memory context. The struct "lua"
Aurelien DARRAGON60ab0f72023-03-01 16:45:50 +01001354 * will be freed.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001355 */
1356void hlua_ctx_destroy(struct hlua *lua)
1357{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001358 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001359 return;
1360
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001361 if (!lua->T)
1362 goto end;
1363
William Lallemandbb581422022-10-20 10:57:28 +02001364 /* clean all running httpclient */
1365 hlua_httpclient_destroy_all(lua);
1366
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001367 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001368 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001369
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001370 if (!SET_SAFE_LJMP(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001371 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001372 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001373 RESET_SAFE_LJMP(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001374
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001375 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001376 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001377 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001378 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001379 /* Forces a garbage collecting process. If the Lua program is finished
1380 * without error, we run the GC on the thread pointer. Its freed all
1381 * the unused memory.
1382 * If the thread is finnish with an error or is currently yielded,
1383 * it seems that the GC applied on the thread doesn't clean anything,
1384 * so e run the GC on the main thread.
1385 * NOTE: maybe this action locks all the Lua threads untiml the en of
1386 * the garbage collection.
1387 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001388 if (lua->gc_count) {
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001389 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001390 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001391 lua_gc(hlua_states[lua->state_id], LUA_GCCOLLECT, 0);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001392 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001393 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001394
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001395 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001396
1397end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001398 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001399}
1400
1401/* This function is used to restore the Lua context when a coroutine
1402 * fails. This function copy the common memory between old coroutine
1403 * and the new coroutine. The old coroutine is destroyed, and its
1404 * replaced by the new coroutine.
1405 * If the flag "keep_msg" is set, the last entry of the old is assumed
1406 * as string error message and it is copied in the new stack.
1407 */
1408static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1409{
1410 lua_State *T;
1411 int new_ref;
1412
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001413 /* New Lua coroutine. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001414 T = lua_newthread(hlua_states[lua->state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001415 if (!T)
1416 return 0;
1417
1418 /* Copy last error message. */
1419 if (keep_msg)
1420 lua_xmove(lua->T, T, 1);
1421
1422 /* Copy data between the coroutines. */
1423 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1424 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001425 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001426
1427 /* Destroy old data. */
1428 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1429
1430 /* The thread is garbage collected by Lua. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001431 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001432
1433 /* Fill the struct with the new coroutine values. */
1434 lua->Mref = new_ref;
1435 lua->T = T;
Thierry Fournier021d9862020-11-28 23:42:03 +01001436 lua->Tref = luaL_ref(hlua_states[lua->state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001437
1438 /* Set context. */
1439 hlua_sethlua(lua);
1440
1441 return 1;
1442}
1443
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001444void hlua_hook(lua_State *L, lua_Debug *ar)
1445{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001446 struct hlua *hlua;
1447
1448 /* Get hlua struct, or NULL if we execute from main lua state */
1449 hlua = hlua_gethlua(L);
1450 if (!hlua)
1451 return;
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001452
1453 /* Lua cannot yield when its returning from a function,
1454 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001455 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001456 */
1457 if (lua_gethookmask(L) & LUA_MASKRET) {
1458 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1459 return;
1460 }
1461
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001462 /* If we interrupt the Lua processing in yieldable state, we yield.
1463 * If the state is not yieldable, trying yield causes an error.
1464 */
Aurelien DARRAGON0ebd41f2022-11-24 09:51:40 +01001465 if (lua_isyieldable(L)) {
1466 /* note: for converters/fetches.. where yielding is not allowed
1467 * hlua_ctx_resume() will simply perform a goto resume_execution
1468 * instead of rescheduling hlua->task.
1469 * also: hlua_ctx_resume() will take care of checking execution
1470 * timeout and re-applying the hook as needed.
1471 */
Willy Tarreau9635e032018-10-16 17:52:55 +02001472 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Aurelien DARRAGON0ebd41f2022-11-24 09:51:40 +01001473 /* lua docs says that the hook should return immediately after lua_yieldk
1474 *
1475 * From: https://www.lua.org/manual/5.3/manual.html#lua_yieldk
1476 *
1477 * Moreover, it seems that we don't want to continue after the yield
1478 * because the end of the function is about handling unyieldable function,
1479 * which is not the case here.
1480 *
1481 * ->if we don't return lua_sethook gets incorrectly set with MASKRET later
1482 * in the function.
1483 */
1484 return;
1485 }
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001486
Thierry FOURNIERa85cfb12015-03-13 14:50:06 +01001487 /* If we cannot yield, update the clock and check the timeout. */
Willy Tarreau55542642021-10-08 09:33:24 +02001488 clock_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001489 hlua->run_time += now_ms - hlua->start_time;
1490 if (hlua->max_time && hlua->run_time >= hlua->max_time) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001491 lua_pushfstring(L, "execution timeout");
1492 WILL_LJMP(lua_error(L));
1493 }
1494
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001495 /* Update the start time. */
1496 hlua->start_time = now_ms;
1497
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001498 /* Try to interrupt the process at the end of the current
1499 * unyieldable function.
1500 */
1501 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001502}
1503
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001504/* This function start or resumes the Lua stack execution. If the flag
1505 * "yield_allowed" if no set and the LUA stack execution returns a yield
1506 * The function return an error.
1507 *
1508 * The function can returns 4 values:
1509 * - HLUA_E_OK : The execution is terminated without any errors.
1510 * - HLUA_E_AGAIN : The execution must continue at the next associated
1511 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001512 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001513 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001514 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001515 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001516 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001517 * LUA code.
1518 */
1519static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1520{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001521#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1522 int nres;
1523#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001524 int ret;
1525 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001526 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001527
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001528 /* Initialise run time counter. */
1529 if (!HLUA_IS_RUNNING(lua))
1530 lua->run_time = 0;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001531
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001532 /* Lock the whole Lua execution. This lock must be before the
1533 * label "resume_execution".
1534 */
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +01001535 hlua_lock(lua);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001536
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001537resume_execution:
1538
1539 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1540 * instructions. it is used for preventing infinite loops.
1541 */
1542 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1543
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001544 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001545 HLUA_SET_RUN(lua);
1546 HLUA_CLR_CTRLYIELD(lua);
1547 HLUA_CLR_WAKERESWR(lua);
1548 HLUA_CLR_WAKEREQWR(lua);
Christopher Faulet1f43a342021-08-04 17:58:21 +02001549 HLUA_CLR_NOYIELD(lua);
1550 if (!yield_allowed)
1551 HLUA_SET_NOYIELD(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001552
Christopher Fauletbc275a92020-02-26 14:55:16 +01001553 /* Update the start time and reset wake_time. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001554 lua->start_time = now_ms;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001555 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001556
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001557 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001558#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournier021d9862020-11-28 23:42:03 +01001559 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs, &nres);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001560#else
Thierry Fournier021d9862020-11-28 23:42:03 +01001561 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001562#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001563 switch (ret) {
1564
1565 case LUA_OK:
1566 ret = HLUA_E_OK;
1567 break;
1568
1569 case LUA_YIELD:
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001570 /* Check if the execution timeout is expired. It it is the case, we
1571 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001572 */
Willy Tarreau55542642021-10-08 09:33:24 +02001573 clock_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001574 lua->run_time += now_ms - lua->start_time;
1575 if (lua->max_time && lua->run_time > lua->max_time) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001576 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001577 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001578 break;
1579 }
1580 /* Process the forced yield. if the general yield is not allowed or
1581 * if no task were associated this the current Lua execution
1582 * coroutine, we resume the execution. Else we want to return in the
1583 * scheduler and we want to be waked up again, to continue the
1584 * current Lua execution. So we schedule our own task.
1585 */
1586 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001587 if (!yield_allowed || !lua->task)
1588 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001589 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001590 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001591 if (!yield_allowed) {
1592 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001593 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001594 break;
1595 }
1596 ret = HLUA_E_AGAIN;
1597 break;
1598
1599 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001600
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001601 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001602 * because the errors ares the only one mean to return immediately
1603 * from and lua execution.
1604 */
1605 if (lua->flags & HLUA_EXIT) {
1606 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001607 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001608 break;
1609 }
1610
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001611 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001612 if (!lua_checkstack(lua->T, 1)) {
1613 ret = HLUA_E_ERR;
1614 break;
1615 }
1616 msg = lua_tostring(lua->T, -1);
1617 lua_settop(lua->T, 0); /* Empty the stack. */
1618 lua_pop(lua->T, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01001619 trace = hlua_traceback(lua->T, ", ");
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001620 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001621 lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001622 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001623 lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001624 ret = HLUA_E_ERRMSG;
1625 break;
1626
1627 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001628 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001629 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001630 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001631 break;
1632
1633 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001634 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001635 if (!lua_checkstack(lua->T, 1)) {
1636 ret = HLUA_E_ERR;
1637 break;
1638 }
1639 msg = lua_tostring(lua->T, -1);
1640 lua_settop(lua->T, 0); /* Empty the stack. */
1641 lua_pop(lua->T, 1);
1642 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001643 lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001644 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001645 lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001646 ret = HLUA_E_ERRMSG;
1647 break;
1648
1649 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001650 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001651 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001652 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001653 break;
1654 }
1655
1656 switch (ret) {
1657 case HLUA_E_AGAIN:
1658 break;
1659
1660 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001661 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001662 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001663 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001664 break;
1665
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001666 case HLUA_E_ETMOUT:
1667 case HLUA_E_NOMEM:
1668 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001669 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001670 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001671 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001672 hlua_ctx_renew(lua, 0);
1673 break;
1674
1675 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001676 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001677 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001678 break;
1679 }
1680
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001681 /* This is the main exit point, remove the Lua lock. */
Aurelien DARRAGONe36f8032023-03-21 13:22:33 +01001682 hlua_unlock(lua);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001683
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001684 return ret;
1685}
1686
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001687/* This function exit the current code. */
1688__LJMP static int hlua_done(lua_State *L)
1689{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001690 struct hlua *hlua;
1691
1692 /* Get hlua struct, or NULL if we execute from main lua state */
1693 hlua = hlua_gethlua(L);
1694 if (!hlua)
1695 return 0;
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001696
1697 hlua->flags |= HLUA_EXIT;
1698 WILL_LJMP(lua_error(L));
1699
1700 return 0;
1701}
1702
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001703/* This function is an LUA binding. It provides a function
1704 * for deleting ACL from a referenced ACL file.
1705 */
1706__LJMP static int hlua_del_acl(lua_State *L)
1707{
1708 const char *name;
1709 const char *key;
1710 struct pat_ref *ref;
1711
1712 MAY_LJMP(check_args(L, 2, "del_acl"));
1713
1714 name = MAY_LJMP(luaL_checkstring(L, 1));
1715 key = MAY_LJMP(luaL_checkstring(L, 2));
1716
1717 ref = pat_ref_lookup(name);
1718 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001719 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001720
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001721 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001722 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001723 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001724 return 0;
1725}
1726
1727/* This function is an LUA binding. It provides a function
1728 * for deleting map entry from a referenced map file.
1729 */
1730static int hlua_del_map(lua_State *L)
1731{
1732 const char *name;
1733 const char *key;
1734 struct pat_ref *ref;
1735
1736 MAY_LJMP(check_args(L, 2, "del_map"));
1737
1738 name = MAY_LJMP(luaL_checkstring(L, 1));
1739 key = MAY_LJMP(luaL_checkstring(L, 2));
1740
1741 ref = pat_ref_lookup(name);
1742 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001743 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001744
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001745 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001746 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001747 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001748 return 0;
1749}
1750
1751/* This function is an LUA binding. It provides a function
1752 * for adding ACL pattern from a referenced ACL file.
1753 */
1754static int hlua_add_acl(lua_State *L)
1755{
1756 const char *name;
1757 const char *key;
1758 struct pat_ref *ref;
1759
1760 MAY_LJMP(check_args(L, 2, "add_acl"));
1761
1762 name = MAY_LJMP(luaL_checkstring(L, 1));
1763 key = MAY_LJMP(luaL_checkstring(L, 2));
1764
1765 ref = pat_ref_lookup(name);
1766 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001767 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001768
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001769 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001770 if (pat_ref_find_elt(ref, key) == NULL)
1771 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001772 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001773 return 0;
1774}
1775
1776/* This function is an LUA binding. It provides a function
1777 * for setting map pattern and sample from a referenced map
1778 * file.
1779 */
1780static int hlua_set_map(lua_State *L)
1781{
1782 const char *name;
1783 const char *key;
1784 const char *value;
1785 struct pat_ref *ref;
1786
1787 MAY_LJMP(check_args(L, 3, "set_map"));
1788
1789 name = MAY_LJMP(luaL_checkstring(L, 1));
1790 key = MAY_LJMP(luaL_checkstring(L, 2));
1791 value = MAY_LJMP(luaL_checkstring(L, 3));
1792
1793 ref = pat_ref_lookup(name);
1794 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001795 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001796
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001797 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001798 if (pat_ref_find_elt(ref, key) != NULL)
1799 pat_ref_set(ref, key, value, NULL);
1800 else
1801 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001802 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001803 return 0;
1804}
1805
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001806/* A class is a lot of memory that contain data. This data can be a table,
1807 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001808 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001809 * the name of the object (_G[<name>] = <metable> ).
1810 *
1811 * A metable is a table that modify the standard behavior of a standard
1812 * access to the associated data. The entries of this new metatable are
1813 * defined as is:
1814 *
1815 * http://lua-users.org/wiki/MetatableEvents
1816 *
1817 * __index
1818 *
1819 * we access an absent field in a table, the result is nil. This is
1820 * true, but it is not the whole truth. Actually, such access triggers
1821 * the interpreter to look for an __index metamethod: If there is no
1822 * such method, as usually happens, then the access results in nil;
1823 * otherwise, the metamethod will provide the result.
1824 *
1825 * Control 'prototype' inheritance. When accessing "myTable[key]" and
1826 * the key does not appear in the table, but the metatable has an __index
1827 * property:
1828 *
1829 * - if the value is a function, the function is called, passing in the
1830 * table and the key; the return value of that function is returned as
1831 * the result.
1832 *
1833 * - if the value is another table, the value of the key in that table is
1834 * asked for and returned (and if it doesn't exist in that table, but that
1835 * table's metatable has an __index property, then it continues on up)
1836 *
1837 * - Use "rawget(myTable,key)" to skip this metamethod.
1838 *
1839 * http://www.lua.org/pil/13.4.1.html
1840 *
1841 * __newindex
1842 *
1843 * Like __index, but control property assignment.
1844 *
1845 * __mode - Control weak references. A string value with one or both
1846 * of the characters 'k' and 'v' which specifies that the the
1847 * keys and/or values in the table are weak references.
1848 *
1849 * __call - Treat a table like a function. When a table is followed by
1850 * parenthesis such as "myTable( 'foo' )" and the metatable has
1851 * a __call key pointing to a function, that function is invoked
1852 * (passing any specified arguments) and the return value is
1853 * returned.
1854 *
1855 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
1856 * called, if the metatable for myTable has a __metatable
1857 * key, the value of that key is returned instead of the
1858 * actual metatable.
1859 *
1860 * __tostring - Control string representation. When the builtin
1861 * "tostring( myTable )" function is called, if the metatable
1862 * for myTable has a __tostring property set to a function,
1863 * that function is invoked (passing myTable to it) and the
1864 * return value is used as the string representation.
1865 *
1866 * __len - Control table length. When the table length is requested using
1867 * the length operator ( '#' ), if the metatable for myTable has
1868 * a __len key pointing to a function, that function is invoked
1869 * (passing myTable to it) and the return value used as the value
1870 * of "#myTable".
1871 *
1872 * __gc - Userdata finalizer code. When userdata is set to be garbage
1873 * collected, if the metatable has a __gc field pointing to a
1874 * function, that function is first invoked, passing the userdata
1875 * to it. The __gc metamethod is not called for tables.
1876 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
1877 *
1878 * Special metamethods for redefining standard operators:
1879 * http://www.lua.org/pil/13.1.html
1880 *
1881 * __add "+"
1882 * __sub "-"
1883 * __mul "*"
1884 * __div "/"
1885 * __unm "!"
1886 * __pow "^"
1887 * __concat ".."
1888 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001889 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001890 * http://www.lua.org/pil/13.2.html
1891 *
1892 * __eq "=="
1893 * __lt "<"
1894 * __le "<="
1895 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001896
1897/*
1898 *
1899 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001900 * Class Map
1901 *
1902 *
1903 */
1904
1905/* Returns a struct hlua_map if the stack entry "ud" is
1906 * a class session, otherwise it throws an error.
1907 */
1908__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
1909{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001910 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001911}
1912
1913/* This function is the map constructor. It don't need
1914 * the class Map object. It creates and return a new Map
1915 * object. It must be called only during "body" or "init"
1916 * context because it process some filesystem accesses.
1917 */
1918__LJMP static int hlua_map_new(struct lua_State *L)
1919{
1920 const char *fn;
1921 int match = PAT_MATCH_STR;
1922 struct sample_conv conv;
1923 const char *file = "";
1924 int line = 0;
1925 lua_Debug ar;
1926 char *err = NULL;
1927 struct arg args[2];
1928
1929 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
1930 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
1931
1932 fn = MAY_LJMP(luaL_checkstring(L, 1));
1933
1934 if (lua_gettop(L) >= 2) {
1935 match = MAY_LJMP(luaL_checkinteger(L, 2));
1936 if (match < 0 || match >= PAT_MATCH_NUM)
1937 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
1938 }
1939
1940 /* Get Lua filename and line number. */
1941 if (lua_getstack(L, 1, &ar)) { /* check function at level */
1942 lua_getinfo(L, "Sl", &ar); /* get info about it */
1943 if (ar.currentline > 0) { /* is there info? */
1944 file = ar.short_src;
1945 line = ar.currentline;
1946 }
1947 }
1948
1949 /* fill fake sample_conv struct. */
1950 conv.kw = ""; /* unused. */
1951 conv.process = NULL; /* unused. */
1952 conv.arg_mask = 0; /* unused. */
1953 conv.val_args = NULL; /* unused. */
1954 conv.out_type = SMP_T_STR;
1955 conv.private = (void *)(long)match;
1956 switch (match) {
1957 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
1958 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
1959 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
1960 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
1961 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
1962 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
1963 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001964 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001965 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
1966 default:
1967 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
1968 }
1969
1970 /* fill fake args. */
1971 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02001972 args[0].data.str.area = strdup(fn);
1973 args[0].data.str.data = strlen(fn);
1974 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001975 args[1].type = ARGT_STOP;
1976
1977 /* load the map. */
1978 if (!sample_load_map(args, &conv, file, line, &err)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001979 /* error case: we can't use luaL_error because we must
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001980 * free the err variable.
1981 */
1982 luaL_where(L, 1);
1983 lua_pushfstring(L, "'new': %s.", err);
1984 lua_concat(L, 2);
1985 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001986 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001987 WILL_LJMP(lua_error(L));
1988 }
1989
1990 /* create the lua object. */
1991 lua_newtable(L);
1992 lua_pushlightuserdata(L, args[0].data.map);
1993 lua_rawseti(L, -2, 0);
1994
1995 /* Pop a class Map metatable and affect it to the userdata. */
1996 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
1997 lua_setmetatable(L, -2);
1998
1999
2000 return 1;
2001}
2002
2003__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
2004{
2005 struct map_descriptor *desc;
2006 struct pattern *pat;
2007 struct sample smp;
2008
2009 MAY_LJMP(check_args(L, 2, "lookup"));
2010 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02002011 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002012 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02002013 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002014 }
2015 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02002016 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002017 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002018 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 +01002019 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002020 }
2021
2022 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02002023 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002024 if (str)
2025 lua_pushstring(L, "");
2026 else
2027 lua_pushnil(L);
2028 return 1;
2029 }
2030
2031 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002032 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02002033 return 1;
2034}
2035
2036__LJMP static int hlua_map_lookup(struct lua_State *L)
2037{
2038 return _hlua_map_lookup(L, 0);
2039}
2040
2041__LJMP static int hlua_map_slookup(struct lua_State *L)
2042{
2043 return _hlua_map_lookup(L, 1);
2044}
2045
2046/*
2047 *
2048 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002049 * Class Socket
2050 *
2051 *
2052 */
2053
2054__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
2055{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002056 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002057}
2058
2059/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002060 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002061 * received.
2062 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002063static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002064{
Willy Tarreau5321da92022-05-06 11:57:34 +02002065 struct hlua_csk_ctx *ctx = appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002066 struct stconn *sc = appctx_sc(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002067
Christopher Faulet31572222023-03-31 11:13:48 +02002068 if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW)))) {
2069 notification_wake(&ctx->wake_on_read);
2070 notification_wake(&ctx->wake_on_write);
2071 return;
2072 }
2073
Willy Tarreau5321da92022-05-06 11:57:34 +02002074 if (ctx->die) {
Christopher Faulet31572222023-03-31 11:13:48 +02002075 se_fl_set(appctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Willy Tarreau5321da92022-05-06 11:57:34 +02002076 notification_wake(&ctx->wake_on_read);
2077 notification_wake(&ctx->wake_on_write);
Christopher Faulet31572222023-03-31 11:13:48 +02002078 return;
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002079 }
2080
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002081 /* If we can't write, wakeup the pending write signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002082 if (channel_output_closed(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002083 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002084
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05002085 /* If we can't read, wakeup the pending read signals. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002086 if (channel_input_closed(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002087 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02002088
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002089 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002090 * to be notified whenever the connection completes.
2091 */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002092 if (sc_opposite(sc)->state < SC_ST_EST) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02002093 applet_need_more_data(appctx);
Willy Tarreaub23edc82022-05-24 16:49:03 +02002094 se_need_remote_conn(appctx->sedesc);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002095 applet_have_more_data(appctx);
Willy Tarreaud4da1962015-04-20 01:31:23 +02002096 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02002097 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002098
2099 /* This function is called after the connect. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002100 ctx->connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002101
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002102 /* Wake the tasks which wants to write if the buffer have available space. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002103 if (channel_may_recv(sc_ic(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002104 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002105
2106 /* Wake the tasks which wants to read if the buffer contains data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02002107 if (!channel_is_empty(sc_oc(sc)))
Willy Tarreau5321da92022-05-06 11:57:34 +02002108 notification_wake(&ctx->wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002109
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002110 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01002111 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002112 */
Willy Tarreau5321da92022-05-06 11:57:34 +02002113 if (notification_registered(&ctx->wake_on_write))
Willy Tarreau4164eb92022-05-25 15:42:03 +02002114 applet_have_more_data(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002115}
2116
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002117static int hlua_socket_init(struct appctx *appctx)
2118{
2119 struct hlua_csk_ctx *ctx = appctx->svcctx;
2120 struct stream *s;
2121
2122 if (appctx_finalize_startup(appctx, socket_proxy, &BUF_NULL) == -1)
2123 goto error;
2124
2125 s = appctx_strm(appctx);
2126
Willy Tarreau4596fe22022-05-17 19:07:51 +02002127 /* Configure "right" stream connector. This stconn is used to connect
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002128 * and retrieve data from the server. The connection is initialized
2129 * with the "struct server".
2130 */
Willy Tarreau74568cf2022-05-27 09:03:30 +02002131 sc_set_state(s->scb, SC_ST_ASS);
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002132
2133 /* Force destination server. */
2134 s->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
2135 s->target = &socket_tcp->obj_type;
2136
2137 ctx->appctx = appctx;
2138 return 0;
2139
2140 error:
2141 return -1;
2142}
2143
Willy Tarreau87b09662015-04-03 00:22:06 +02002144/* This function is called when the "struct stream" is destroyed.
2145 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002146 * Wake all the pending signals.
2147 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002148static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002149{
Willy Tarreau5321da92022-05-06 11:57:34 +02002150 struct hlua_csk_ctx *ctx = appctx->svcctx;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002151 struct xref *peer;
2152
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002153 /* Remove my link in the original objects. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002154 peer = xref_get_peer_and_lock(&ctx->xref);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002155 if (peer)
Willy Tarreau5321da92022-05-06 11:57:34 +02002156 xref_disconnect(&ctx->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002157
2158 /* Wake all the task waiting for me. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002159 notification_wake(&ctx->wake_on_read);
2160 notification_wake(&ctx->wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002161}
2162
2163/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02002164 * uses this object. If the stream does not exists, just quit.
2165 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002166 * pending signal can rest in the read and write lists. destroy
2167 * it.
2168 */
2169__LJMP static int hlua_socket_gc(lua_State *L)
2170{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002171 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002172 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002173 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002174
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002175 MAY_LJMP(check_args(L, 1, "__gc"));
2176
2177 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002178 peer = xref_get_peer_and_lock(&socket->xref);
2179 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002180 return 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02002181
2182 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002183
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002184 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002185 ctx->die = 1;
2186 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002187
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002188 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002189 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002190 return 0;
2191}
2192
2193/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02002194 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002195 */
sada05ed3302018-05-11 11:48:18 -07002196__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002197{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002198 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02002199 struct hlua_csk_ctx *ctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002200 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002201 struct hlua *hlua;
2202
2203 /* Get hlua struct, or NULL if we execute from main lua state */
2204 hlua = hlua_gethlua(L);
2205 if (!hlua)
2206 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002207
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002208 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002209
2210 /* Check if we run on the same thread than the xreator thread.
2211 * We cannot access to the socket if the thread is different.
2212 */
2213 if (socket->tid != tid)
2214 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2215
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002216 peer = xref_get_peer_and_lock(&socket->xref);
2217 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002218 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01002219
2220 hlua->gc_count--;
Willy Tarreau5321da92022-05-06 11:57:34 +02002221 ctx = container_of(peer, struct hlua_csk_ctx, xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002222
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002223 /* Set the flag which destroy the session. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002224 ctx->die = 1;
2225 appctx_wakeup(ctx->appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002226
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002227 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002228 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002229 return 0;
2230}
2231
sada05ed3302018-05-11 11:48:18 -07002232/* The close function calls close_helper.
2233 */
2234__LJMP static int hlua_socket_close(lua_State *L)
2235{
2236 MAY_LJMP(check_args(L, 1, "close"));
2237 return hlua_socket_close_helper(L);
2238}
2239
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002240/* This Lua function assumes that the stack contain three parameters.
2241 * 1 - USERDATA containing a struct socket
2242 * 2 - INTEGER with values of the macro defined below
2243 * If the integer is -1, we must read at most one line.
2244 * If the integer is -2, we ust read all the data until the
2245 * end of the stream.
2246 * If the integer is positive value, we must read a number of
2247 * bytes corresponding to this value.
2248 */
2249#define HLSR_READ_LINE (-1)
2250#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002251__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002252{
2253 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
2254 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002255 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002256 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002257 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002258 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002259 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02002260 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002261 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02002262 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002263 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002264 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01002265 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002266 struct stream *s;
2267 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002268 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002269
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002270 /* Get hlua struct, or NULL if we execute from main lua state */
2271 hlua = hlua_gethlua(L);
2272
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002273 /* Check if this lua stack is schedulable. */
2274 if (!hlua || !hlua->task)
2275 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
2276 "'frontend', 'backend' or 'task'"));
2277
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002278 /* Check if we run on the same thread than the xreator thread.
2279 * We cannot access to the socket if the thread is different.
2280 */
2281 if (socket->tid != tid)
2282 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2283
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002284 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002285 peer = xref_get_peer_and_lock(&socket->xref);
2286 if (!peer)
2287 goto no_peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002288
2289 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2290 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002291 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002292
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002293 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002294 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002295 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002296 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002297 if (nblk < 0) /* Connection close. */
2298 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002299 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002300 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002301
2302 /* remove final \r\n. */
2303 if (nblk == 1) {
2304 if (blk1[len1-1] == '\n') {
2305 len1--;
2306 skip_at_end++;
2307 if (blk1[len1-1] == '\r') {
2308 len1--;
2309 skip_at_end++;
2310 }
2311 }
2312 }
2313 else {
2314 if (blk2[len2-1] == '\n') {
2315 len2--;
2316 skip_at_end++;
2317 if (blk2[len2-1] == '\r') {
2318 len2--;
2319 skip_at_end++;
2320 }
2321 }
2322 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002323 }
2324
2325 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002326 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002327 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002328 if (nblk < 0) /* Connection close. */
2329 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002330 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002331 goto connection_empty;
2332 }
2333
2334 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002335 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002336 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002337 if (nblk < 0) /* Connection close. */
2338 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002339 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002340 goto connection_empty;
2341
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002342 missing_bytes = wanted - socket->b.n;
2343 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002344 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002345 len1 = missing_bytes;
2346 } if (nblk == 2 && len1 + len2 > missing_bytes)
2347 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002348 }
2349
2350 len = len1;
2351
2352 luaL_addlstring(&socket->b, blk1, len1);
2353 if (nblk == 2) {
2354 len += len2;
2355 luaL_addlstring(&socket->b, blk2, len2);
2356 }
2357
2358 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002359 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002360
2361 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002362 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002363
2364 /* If the pattern reclaim to read all the data
2365 * in the connection, got out.
2366 */
2367 if (wanted == HLSR_READ_ALL)
2368 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002369 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002370 goto connection_empty;
2371
2372 /* Return result. */
2373 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002374 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002375 return 1;
2376
2377connection_closed:
2378
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002379 xref_unlock(&socket->xref, peer);
2380
2381no_peer:
2382
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002383 /* If the buffer containds data. */
2384 if (socket->b.n > 0) {
2385 luaL_pushresult(&socket->b);
2386 return 1;
2387 }
2388 lua_pushnil(L);
2389 lua_pushstring(L, "connection closed.");
2390 return 2;
2391
2392connection_empty:
2393
Willy Tarreau5321da92022-05-06 11:57:34 +02002394 if (!notification_new(&hlua->com, &csk_ctx->wake_on_read, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002395 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002396 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002397 }
2398 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002399 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002400 return 0;
2401}
2402
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002403/* This Lua function gets two parameters. The first one can be string
2404 * or a number. If the string is "*l", the user requires one line. If
2405 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002406 * If the value is a number, the user require a number of bytes equal
2407 * to the value. The default value is "*l" (a line).
2408 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002409 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002410 * integer takes this values:
2411 * -1 : read a line
2412 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002413 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002414 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002415 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002416 * concatenated with the read data.
2417 */
2418__LJMP static int hlua_socket_receive(struct lua_State *L)
2419{
2420 int wanted = HLSR_READ_LINE;
2421 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002422 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002423 char *error;
2424 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002425 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002426
2427 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2428 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2429
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002430 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002431
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002432 /* Check if we run on the same thread than the xreator thread.
2433 * We cannot access to the socket if the thread is different.
2434 */
2435 if (socket->tid != tid)
2436 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2437
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002438 /* check for pattern. */
2439 if (lua_gettop(L) >= 2) {
2440 type = lua_type(L, 2);
2441 if (type == LUA_TSTRING) {
2442 pattern = lua_tostring(L, 2);
2443 if (strcmp(pattern, "*a") == 0)
2444 wanted = HLSR_READ_ALL;
2445 else if (strcmp(pattern, "*l") == 0)
2446 wanted = HLSR_READ_LINE;
2447 else {
2448 wanted = strtoll(pattern, &error, 10);
2449 if (*error != '\0')
2450 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2451 }
2452 }
2453 else if (type == LUA_TNUMBER) {
2454 wanted = lua_tointeger(L, 2);
2455 if (wanted < 0)
2456 WILL_LJMP(luaL_error(L, "Unsupported size."));
2457 }
2458 }
2459
2460 /* Set pattern. */
2461 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002462
2463 /* Check if we would replace the top by itself. */
2464 if (lua_gettop(L) != 2)
2465 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002466
Christopher Fauletc31b2002021-05-03 10:11:13 +02002467 /* Save index of the top of the stack because since buffers are used, it
2468 * may change
2469 */
2470 lastarg = lua_gettop(L);
2471
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002472 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002473 luaL_buffinit(L, &socket->b);
2474
2475 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002476 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002477 if (lua_type(L, 3) != LUA_TSTRING)
2478 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2479 pattern = lua_tolstring(L, 3, &len);
2480 luaL_addlstring(&socket->b, pattern, len);
2481 }
2482
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002483 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002484}
2485
2486/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002487 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002488 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002489static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002490{
2491 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002492 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002493 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002494 struct appctx *appctx;
2495 size_t buf_len;
2496 const char *buf;
2497 int len;
2498 int send_len;
2499 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002500 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002501 struct stream *s;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002502 struct stconn *sc;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002503
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002504 /* Get hlua struct, or NULL if we execute from main lua state */
2505 hlua = hlua_gethlua(L);
2506
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002507 /* Check if this lua stack is schedulable. */
2508 if (!hlua || !hlua->task)
2509 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2510 "'frontend', 'backend' or 'task'"));
2511
2512 /* Get object */
2513 socket = MAY_LJMP(hlua_checksocket(L, 1));
2514 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002515 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002516
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002517 /* Check if we run on the same thread than the xreator thread.
2518 * We cannot access to the socket if the thread is different.
2519 */
2520 if (socket->tid != tid)
2521 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2522
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002523 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002524 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002525 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002526 lua_pushinteger(L, -1);
2527 return 1;
2528 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002529
2530 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2531 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002532 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002533 s = __sc_strm(sc);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002534
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002535 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002536 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002537 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002538 lua_pushinteger(L, -1);
2539 return 1;
2540 }
2541
2542 /* Update the input buffer data. */
2543 buf += sent;
2544 send_len = buf_len - sent;
2545
2546 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002547 if (sent >= buf_len) {
2548 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002549 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002550 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002551
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002552 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002553 * the request buffer if its not required.
2554 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002555 if (s->req.buf.size == 0) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02002556 if (!sc_alloc_ibuf(sc, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002557 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002558 }
2559
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002560 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002561 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002562 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002563 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002564 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002565
2566 /* send data */
2567 if (len < send_len)
2568 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002569 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002570
2571 /* "Not enough space" (-1), "Buffer too little to contain
2572 * the data" (-2) are not expected because the available length
2573 * is tested.
2574 * Other unknown error are also not expected.
2575 */
2576 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002577 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002578 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002579
sada05ed3302018-05-11 11:48:18 -07002580 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002581 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002582 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002583 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002584 return 1;
2585 }
2586
2587 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002588 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002589
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002590 /* Update length sent. */
2591 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002592 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002593
2594 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002595 if (sent + len >= buf_len) {
2596 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002597 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002598 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002599
2600hlua_socket_write_yield_return:
Willy Tarreau5321da92022-05-06 11:57:34 +02002601 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002602 xref_unlock(&socket->xref, peer);
2603 WILL_LJMP(luaL_error(L, "out of memory"));
2604 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002605 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002606 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002607 return 0;
2608}
2609
2610/* This function initiate the send of data. It just check the input
2611 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002612 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002613 * "hlua_socket_write_yield" that can yield.
2614 *
2615 * The Lua function gets between 3 and 4 parameters. The first one is
2616 * the associated object. The second is a string buffer. The third is
2617 * a facultative integer that represents where is the buffer position
2618 * of the start of the data that can send. The first byte is the
2619 * position "1". The default value is "1". The fourth argument is a
2620 * facultative integer that represents where is the buffer position
2621 * of the end of the data that can send. The default is the last byte.
2622 */
2623static int hlua_socket_send(struct lua_State *L)
2624{
2625 int i;
2626 int j;
2627 const char *buf;
2628 size_t buf_len;
2629
2630 /* Check number of arguments. */
2631 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2632 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2633
2634 /* Get the string. */
2635 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2636
2637 /* Get and check j. */
2638 if (lua_gettop(L) == 4) {
2639 j = MAY_LJMP(luaL_checkinteger(L, 4));
2640 if (j < 0)
2641 j = buf_len + j + 1;
2642 if (j > buf_len)
2643 j = buf_len + 1;
2644 lua_pop(L, 1);
2645 }
2646 else
2647 j = buf_len;
2648
2649 /* Get and check i. */
2650 if (lua_gettop(L) == 3) {
2651 i = MAY_LJMP(luaL_checkinteger(L, 3));
2652 if (i < 0)
2653 i = buf_len + i + 1;
2654 if (i > buf_len)
2655 i = buf_len + 1;
2656 lua_pop(L, 1);
2657 } else
2658 i = 1;
2659
2660 /* Check bth i and j. */
2661 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002662 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002663 return 1;
2664 }
2665 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002666 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002667 return 1;
2668 }
2669 if (i == 0)
2670 i = 1;
2671 if (j == 0)
2672 j = 1;
2673
2674 /* Pop the string. */
2675 lua_pop(L, 1);
2676
2677 /* Update the buffer length. */
2678 buf += i - 1;
2679 buf_len = j - i + 1;
2680 lua_pushlstring(L, buf, buf_len);
2681
2682 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002683 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002684
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002685 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002686}
2687
Willy Tarreau22b0a682015-06-17 19:43:49 +02002688#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Christopher Faulete6465b32021-10-22 15:36:08 +02002689__LJMP static inline int hlua_socket_info(struct lua_State *L, const struct sockaddr_storage *addr)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002690{
2691 static char buffer[SOCKET_INFO_MAX_LEN];
2692 int ret;
2693 int len;
2694 char *p;
2695
2696 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2697 if (ret <= 0) {
2698 lua_pushnil(L);
2699 return 1;
2700 }
2701
2702 if (ret == AF_UNIX) {
2703 lua_pushstring(L, buffer+1);
2704 return 1;
2705 }
2706 else if (ret == AF_INET6) {
2707 buffer[0] = '[';
2708 len = strlen(buffer);
2709 buffer[len] = ']';
2710 len++;
2711 buffer[len] = ':';
2712 len++;
2713 p = buffer;
2714 }
2715 else if (ret == AF_INET) {
2716 p = buffer + 1;
2717 len = strlen(p);
2718 p[len] = ':';
2719 len++;
2720 }
2721 else {
2722 lua_pushnil(L);
2723 return 1;
2724 }
2725
2726 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2727 lua_pushnil(L);
2728 return 1;
2729 }
2730
2731 lua_pushstring(L, p);
2732 return 1;
2733}
2734
2735/* Returns information about the peer of the connection. */
2736__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2737{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002738 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002739 struct xref *peer;
2740 struct appctx *appctx;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002741 struct stconn *sc;
Christopher Faulet16f16af2021-10-27 09:34:56 +02002742 const struct sockaddr_storage *dst;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002743 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002744
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002745 MAY_LJMP(check_args(L, 1, "getpeername"));
2746
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002747 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002748
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002749 /* Check if we run on the same thread than the xreator thread.
2750 * We cannot access to the socket if the thread is different.
2751 */
2752 if (socket->tid != tid)
2753 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2754
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002755 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002756 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002757 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002758 lua_pushnil(L);
2759 return 1;
2760 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002761
2762 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002763 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002764 dst = sc_dst(sc_opposite(sc));
Christopher Faulet16f16af2021-10-27 09:34:56 +02002765 if (!dst) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002766 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002767 lua_pushnil(L);
2768 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002769 }
2770
Christopher Faulet16f16af2021-10-27 09:34:56 +02002771 ret = MAY_LJMP(hlua_socket_info(L, dst));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002772 xref_unlock(&socket->xref, peer);
2773 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002774}
2775
2776/* Returns information about my connection side. */
2777static int hlua_socket_getsockname(struct lua_State *L)
2778{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002779 struct hlua_socket *socket;
2780 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002781 struct appctx *appctx;
2782 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002783 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002784 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002785
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002786 MAY_LJMP(check_args(L, 1, "getsockname"));
2787
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002788 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002789
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002790 /* Check if we run on the same thread than the xreator thread.
2791 * We cannot access to the socket if the thread is different.
2792 */
2793 if (socket->tid != tid)
2794 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2795
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002796 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002797 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002798 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002799 lua_pushnil(L);
2800 return 1;
2801 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002802
2803 appctx = container_of(peer, struct hlua_csk_ctx, xref)->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002804 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002805
Willy Tarreaufd9417b2022-05-18 16:23:22 +02002806 conn = sc_conn(s->scb);
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002807 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002808 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002809 lua_pushnil(L);
2810 return 1;
2811 }
2812
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002813 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002814 xref_unlock(&socket->xref, peer);
2815 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002816}
2817
2818/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002819static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002820 .obj_type = OBJ_TYPE_APPLET,
2821 .name = "<LUA_TCP>",
2822 .fct = hlua_socket_handler,
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02002823 .init = hlua_socket_init,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002824 .release = hlua_socket_release,
2825};
2826
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002827__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002828{
2829 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002830 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002831 struct xref *peer;
Willy Tarreau5321da92022-05-06 11:57:34 +02002832 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002833 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002834 struct stream *s;
2835
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002836 /* Get hlua struct, or NULL if we execute from main lua state */
2837 hlua = hlua_gethlua(L);
2838 if (!hlua)
2839 return 0;
2840
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002841 /* Check if we run on the same thread than the xreator thread.
2842 * We cannot access to the socket if the thread is different.
2843 */
2844 if (socket->tid != tid)
2845 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2846
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002847 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002848 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002849 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002850 lua_pushnil(L);
2851 lua_pushstring(L, "Can't connect");
2852 return 2;
2853 }
Willy Tarreau5321da92022-05-06 11:57:34 +02002854
2855 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2856 appctx = csk_ctx->appctx;
Willy Tarreau0698c802022-05-11 14:09:57 +02002857 s = appctx_strm(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002858
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002859 /* Check if we run on the same thread than the xreator thread.
2860 * We cannot access to the socket if the thread is different.
2861 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002862 if (socket->tid != tid) {
2863 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002864 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002865 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002866
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002867 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002868 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002869 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002870 lua_pushnil(L);
2871 lua_pushstring(L, "Can't connect");
2872 return 2;
2873 }
2874
Willy Tarreau8e7c6e62022-05-18 17:58:02 +02002875 appctx = __sc_appctx(s->scf);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002876
2877 /* Check for connection established. */
Willy Tarreau5321da92022-05-06 11:57:34 +02002878 if (csk_ctx->connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002879 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002880 lua_pushinteger(L, 1);
2881 return 1;
2882 }
2883
Willy Tarreau5321da92022-05-06 11:57:34 +02002884 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002885 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002886 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002887 }
2888 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002889 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002890 return 0;
2891}
2892
2893/* This function fail or initite the connection. */
2894__LJMP static int hlua_socket_connect(struct lua_State *L)
2895{
2896 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002897 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002898 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002899 struct hlua *hlua;
Willy Tarreau5321da92022-05-06 11:57:34 +02002900 struct hlua_csk_ctx *csk_ctx;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002901 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002902 int low, high;
2903 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002904 struct xref *peer;
Willy Tarreau3e7be362022-05-27 10:35:27 +02002905 struct stconn *sc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002906 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002907
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002908 if (lua_gettop(L) < 2)
2909 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002910
2911 /* Get args. */
2912 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002913
2914 /* Check if we run on the same thread than the xreator thread.
2915 * We cannot access to the socket if the thread is different.
2916 */
2917 if (socket->tid != tid)
2918 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2919
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002920 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002921 if (lua_gettop(L) >= 3) {
2922 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002923 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002924
Tim Duesterhus6edab862018-01-06 19:04:45 +01002925 /* Force the ip to end with a colon, to support IPv6 addresses
2926 * that are not enclosed within square brackets.
2927 */
2928 if (port > 0) {
2929 luaL_buffinit(L, &b);
2930 luaL_addstring(&b, ip);
2931 luaL_addchar(&b, ':');
2932 luaL_pushresult(&b);
2933 ip = lua_tolstring(L, lua_gettop(L), NULL);
2934 }
2935 }
2936
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002937 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002938 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002939 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002940 lua_pushnil(L);
2941 return 1;
2942 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002943
2944 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002945 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 +02002946 if (!addr) {
2947 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002948 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002949 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002950
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002951 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002952 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002953 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002954 if (port == -1) {
2955 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002956 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002957 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002958 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2959 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002960 if (port == -1) {
2961 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002962 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002963 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002964 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002965 }
2966 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002967
Willy Tarreau5321da92022-05-06 11:57:34 +02002968 csk_ctx = container_of(peer, struct hlua_csk_ctx, xref);
2969 appctx = csk_ctx->appctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02002970 sc = appctx_sc(appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02002971 s = __sc_strm(sc);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002972
Willy Tarreau3e7be362022-05-27 10:35:27 +02002973 if (!sockaddr_alloc(&sc_opposite(sc)->dst, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002974 xref_unlock(&socket->xref, peer);
2975 WILL_LJMP(luaL_error(L, "connect: internal error"));
2976 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002977
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002978 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002979 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002980 if (!hlua)
2981 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002982
2983 /* inform the stream that we want to be notified whenever the
2984 * connection completes.
2985 */
Willy Tarreau90e8b452022-05-25 18:21:43 +02002986 applet_need_more_data(appctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02002987 applet_have_more_data(appctx);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002988 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002989
Willy Tarreauf31af932020-01-14 09:59:38 +01002990 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002991
Willy Tarreau5321da92022-05-06 11:57:34 +02002992 if (!notification_new(&hlua->com, &csk_ctx->wake_on_write, hlua->task)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002993 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002994 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002995 }
2996 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002997
2998 task_wakeup(s->task, TASK_WOKEN_INIT);
2999 /* Return yield waiting for connection. */
3000
Willy Tarreau9635e032018-10-16 17:52:55 +02003001 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003002
3003 return 0;
3004}
3005
Baptiste Assmann84bb4932015-03-02 21:40:06 +01003006#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003007__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
3008{
3009 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003010 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003011 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003012
3013 MAY_LJMP(check_args(L, 3, "connect_ssl"));
3014 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003015
3016 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003017 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003018 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003019 lua_pushnil(L);
3020 return 1;
3021 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003022
Willy Tarreau0698c802022-05-11 14:09:57 +02003023 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003024
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01003025 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003026 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003027 return MAY_LJMP(hlua_socket_connect(L));
3028}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01003029#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003030
3031__LJMP static int hlua_socket_setoption(struct lua_State *L)
3032{
3033 return 0;
3034}
3035
3036__LJMP static int hlua_socket_settimeout(struct lua_State *L)
3037{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003038 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003039 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02003040 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003041 struct xref *peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003042 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003043
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003044 MAY_LJMP(check_args(L, 2, "settimeout"));
3045
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003046 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02003047
Cyril Bonté7ee465f2018-08-19 22:08:50 +02003048 /* convert the timeout to millis */
3049 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003050
Thierry Fournier17a921b2018-03-08 09:59:02 +01003051 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02003052 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01003053 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
3054
Mark Lakes56cc1252018-03-27 09:48:06 +02003055 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02003056 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02003057
3058 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02003059 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003060 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02003061
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003062 /* Check if we run on the same thread than the xreator thread.
3063 * We cannot access to the socket if the thread is different.
3064 */
3065 if (socket->tid != tid)
3066 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
3067
Mark Lakes56cc1252018-03-27 09:48:06 +02003068 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003069 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003070 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003071 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
3072 WILL_LJMP(lua_error(L));
3073 return 0;
3074 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003075
Willy Tarreau0698c802022-05-11 14:09:57 +02003076 s = appctx_strm(container_of(peer, struct hlua_csk_ctx, xref)->appctx);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003077
Cyril Bonté7bb63452018-08-17 23:51:02 +02003078 s->sess->fe->timeout.connect = tmout;
Christopher Faulet5aaacfb2023-02-15 08:13:33 +01003079 s->scf->ioto = tmout;
3080 s->scb->ioto = tmout;
Cyril Bonté7bb63452018-08-17 23:51:02 +02003081
3082 s->task->expire = tick_add_ifset(now_ms, tmout);
3083 task_queue(s->task);
3084
Thierry FOURNIER952939d2017-09-01 14:17:32 +02003085 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003086
Thierry Fourniere9636f12018-03-08 09:54:32 +01003087 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01003088 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003089}
3090
3091__LJMP static int hlua_socket_new(lua_State *L)
3092{
3093 struct hlua_socket *socket;
Willy Tarreau5321da92022-05-06 11:57:34 +02003094 struct hlua_csk_ctx *ctx;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003095 struct appctx *appctx;
3096
3097 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003098 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003099 hlua_pusherror(L, "socket: full stack");
3100 goto out_fail_conf;
3101 }
3102
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003103 /* Create the object: obj[0] = userdata. */
3104 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003105 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003106 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003107 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02003108 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003109
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003110 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01003111 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01003112 hlua_pusherror(L, "socket: uninitialized pools.");
3113 goto out_fail_conf;
3114 }
3115
Willy Tarreau87b09662015-04-03 00:22:06 +02003116 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003117 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
3118 lua_setmetatable(L, -2);
3119
Willy Tarreaud420a972015-04-06 00:39:18 +02003120 /* Create the applet context */
Christopher Faulet6095d572022-05-16 17:09:48 +02003121 appctx = appctx_new_here(&update_applet, NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003122 if (!appctx) {
3123 hlua_pusherror(L, "socket: out of memory");
Christopher Fauleta9e8b392022-03-23 11:01:09 +01003124 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02003125 }
Willy Tarreau5321da92022-05-06 11:57:34 +02003126 ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
3127 ctx->connected = 0;
Willy Tarreau5321da92022-05-06 11:57:34 +02003128 ctx->die = 0;
3129 LIST_INIT(&ctx->wake_on_write);
3130 LIST_INIT(&ctx->wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02003131
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003132 if (appctx_init(appctx) == -1) {
3133 hlua_pusherror(L, "socket: fail to init applet.");
Christopher Faulet13a35e52021-12-20 15:34:16 +01003134 goto out_fail_appctx;
3135 }
3136
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02003137 /* Initialise cross reference between stream and Lua socket object. */
Willy Tarreau5321da92022-05-06 11:57:34 +02003138 xref_create(&socket->xref, &ctx->xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003139 return 1;
3140
Christopher Faulet13a35e52021-12-20 15:34:16 +01003141 out_fail_appctx:
Christopher Faulet5f35a3e2022-05-12 15:31:05 +02003142 appctx_free_on_early_error(appctx);
Willy Tarreaud420a972015-04-06 00:39:18 +02003143 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01003144 WILL_LJMP(lua_error(L));
3145 return 0;
3146}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01003147
3148/*
3149 *
3150 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003151 * Class Channel
3152 *
3153 *
3154 */
3155
3156/* Returns the struct hlua_channel join to the class channel in the
3157 * stack entry "ud" or throws an argument error.
3158 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003159__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003160{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003161 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003162}
3163
Willy Tarreau47860ed2015-03-10 14:07:50 +01003164/* Pushes the channel onto the top of the stack. If the stask does not have a
3165 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003166 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01003167static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003168{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003169 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003170 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003171 return 0;
3172
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003173 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003174 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01003175 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003176
3177 /* Pop a class sesison metatable and affect it to the userdata. */
3178 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
3179 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003180 return 1;
3181}
3182
Christopher Faulet9f55a502020-02-25 15:21:02 +01003183/* Helper function returning a filter attached to a channel at the position <ud>
3184 * in the stack, filling the current offset and length of the filter. If no
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05003185 * filter is attached, NULL is returned and <offset> and <len> are not
Christopher Faulet9f55a502020-02-25 15:21:02 +01003186 * initialized.
3187 */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003188static 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 +01003189{
3190 struct filter *filter = NULL;
3191
3192 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
3193 struct hlua_flt_ctx *flt_ctx;
3194
3195 filter = lua_touserdata (L, -1);
3196 flt_ctx = filter->ctx;
3197 if (hlua_filter_from_payload(filter)) {
3198 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
3199 *len = flt_ctx->cur_len[CHN_IDX(chn)];
3200 }
3201 }
3202
3203 lua_pop(L, 1);
3204 return filter;
3205}
3206
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003207/* Copies <len> bytes of data present in the channel's buffer, starting at the
3208* offset <offset>, and put it in a LUA string variable. It is the caller
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003209* responsibility to ensure <len> and <offset> are valid. It always return the
3210* length of the built string. <len> may be 0, in this case, an empty string is
3211* created and 0 is returned.
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003212*/
3213static inline int _hlua_channel_dup(struct channel *chn, lua_State *L, size_t offset, size_t len)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003214{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003215 size_t block1, block2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003216 luaL_Buffer b;
3217
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003218 block1 = len;
3219 if (block1 > b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset)))
3220 block1 = b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset));
3221 block2 = len - block1;
3222
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003223 luaL_buffinit(L, &b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003224 luaL_addlstring(&b, b_peek(&chn->buf, offset), block1);
3225 if (block2)
3226 luaL_addlstring(&b, b_orig(&chn->buf), block2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003227 luaL_pushresult(&b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003228 return len;
3229}
3230
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003231/* Inserts the string <str> to the channel's buffer at the offset <offset>. This
3232 * function returns -1 if data cannot be copied. Otherwise, it returns the
3233 * number of bytes copied.
3234 */
3235static int _hlua_channel_insert(struct channel *chn, lua_State *L, struct ist str, size_t offset)
3236{
3237 int ret = 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003238
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003239 /* Nothing to do, just return */
3240 if (unlikely(istlen(str) == 0))
3241 goto end;
3242
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003243 if (istlen(str) > c_room(chn)) {
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003244 ret = -1;
3245 goto end;
3246 }
3247 ret = b_insert_blk(&chn->buf, offset, istptr(str), istlen(str));
3248
3249 end:
3250 return ret;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003251}
3252
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003253/* Removes <len> bytes of data at the absolute position <offset>.
3254 */
3255static void _hlua_channel_delete(struct channel *chn, size_t offset, size_t len)
3256{
3257 size_t end = offset + len;
3258
3259 if (b_peek(&chn->buf, end) != b_tail(&chn->buf))
3260 b_move(&chn->buf, b_peek_ofs(&chn->buf, end),
3261 b_data(&chn->buf) - end, -len);
3262 b_sub(&chn->buf, len);
3263}
3264
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003265/* Copies input data in the channel's buffer. It is possible to set a specific
3266 * offset (0 by default) and a length (all remaining input data starting for the
3267 * offset by default). If there is not enough input data and more data can be
3268 * received, this function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003269 *
3270 * From an action, All input data are considered. For a filter, the offset and
3271 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003272 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003273__LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003274{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003275 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003276 struct filter *filter;
3277 size_t input, output;
3278 int offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003279
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003280 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003281
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003282 output = co_data(chn);
3283 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003284
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003285 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3286 if (filter && !hlua_filter_from_payload(filter))
3287 WILL_LJMP(lua_error(L));
3288
3289 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003290 if (lua_gettop(L) > 1) {
3291 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3292 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003293 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003294 offset += output;
3295 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003296 lua_pushfstring(L, "offset out of range.");
3297 WILL_LJMP(lua_error(L));
3298 }
3299 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003300 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003301 if (lua_gettop(L) == 3) {
3302 len = MAY_LJMP(luaL_checkinteger(L, 3));
3303 if (!len)
3304 goto dup;
3305 if (len == -1)
3306 len = global.tune.bufsize;
3307 if (len < 0) {
3308 lua_pushfstring(L, "length out of range.");
3309 WILL_LJMP(lua_error(L));
3310 }
3311 }
3312
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003313 /* Wait for more data if possible if no length was specified and there
3314 * is no data or not enough data was received.
3315 */
3316 if (!len || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003317 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3318 /* Yield waiting for more data, as requested */
3319 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_data_yield, TICK_ETERNITY, 0));
3320 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003321
3322 /* Return 'nil' if there is no data and the channel can't receive more data */
3323 if (!len) {
3324 lua_pushnil(L);
3325 return -1;
3326 }
3327
3328 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003329 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003330 }
3331
3332 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003333 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003334 return 1;
3335}
3336
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003337/* Copies the first line (including the trailing LF) of input data in the
3338 * channel's buffer. It is possible to set a specific offset (0 by default) and
3339 * a length (all remaining input data starting for the offset by default). If
3340 * there is not enough input data and more data can be received, the function
3341 * yields. If a length is explicitly specified, no more data are
3342 * copied. Otherwise, if no LF is found and more data can be received, this
3343 * function yields.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003344 *
3345 * From an action, All input data are considered. For a filter, the offset and
3346 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003347 */
3348__LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003349{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003350 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003351 struct filter *filter;
3352 size_t l, input, output;
3353 int offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003354
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003355 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003356 output = co_data(chn);
3357 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003358
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003359 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3360 if (filter && !hlua_filter_from_payload(filter))
3361 WILL_LJMP(lua_error(L));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003362
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003363 offset = output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003364 if (lua_gettop(L) > 1) {
3365 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3366 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003367 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003368 offset += output;
3369 if (offset < output || offset > input + output) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003370 lua_pushfstring(L, "offset out of range.");
3371 WILL_LJMP(lua_error(L));
3372 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003373 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003374
3375 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003376 if (lua_gettop(L) == 3) {
3377 len = MAY_LJMP(luaL_checkinteger(L, 3));
3378 if (!len)
3379 goto dup;
3380 if (len == -1)
3381 len = global.tune.bufsize;
3382 if (len < 0) {
3383 lua_pushfstring(L, "length out of range.");
3384 WILL_LJMP(lua_error(L));
3385 }
3386 }
3387
3388 for (l = 0; l < len; l++) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003389 if (l + offset >= output + input)
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003390 break;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003391 if (*(b_peek(&chn->buf, offset + l)) == '\n') {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003392 len = l+1;
3393 goto dup;
3394 }
3395 }
3396
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003397 /* Wait for more data if possible if no line is found and no length was
3398 * specified or not enough data was received.
3399 */
3400 if (lua_gettop(L) != 3 || offset + len > output + input) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003401 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3402 /* Yield waiting for more data */
3403 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_line_yield, TICK_ETERNITY, 0));
3404 }
Christopher Faulet0ae2e632023-01-10 15:29:54 +01003405
3406 /* Return 'nil' if there is no data and the channel can't receive more data */
3407 if (!len) {
3408 lua_pushnil(L);
3409 return -1;
3410 }
3411
3412 /* Otherwise, return all data */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003413 len = output + input - offset;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003414 }
3415
3416 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003417 _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003418 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003419}
3420
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003421/* [ DEPRECATED ]
3422 *
3423 * Duplicate all input data foud in the channel's buffer. The data are not
3424 * removed from the buffer. This function relies on _hlua_channel_dup().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003425 *
3426 * From an action, All input data are considered. For a filter, the offset and
3427 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003428 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003429__LJMP static int hlua_channel_dup(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003430{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003431 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003432 struct filter *filter;
3433 size_t offset, len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003434
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003435 MAY_LJMP(check_args(L, 1, "dup"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003436 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003437 if (IS_HTX_STRM(chn_strm(chn))) {
3438 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3439 WILL_LJMP(lua_error(L));
3440 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003441
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003442 offset = co_data(chn);
3443 len = ci_data(chn);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003444
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003445 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3446 if (filter && !hlua_filter_from_payload(filter))
3447 WILL_LJMP(lua_error(L));
3448
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003449 if (!ci_data(chn) && channel_input_closed(chn)) {
3450 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003451 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003452 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003453
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003454 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003455 return 1;
3456}
3457
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003458/* [ DEPRECATED ]
3459 *
3460 * Get all input data foud in the channel's buffer. The data are removed from
3461 * the buffer after the copy. This function relies on _hlua_channel_dup() and
3462 * _hlua_channel_delete().
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003463 *
3464 * From an action, All input data are considered. For a filter, the offset and
3465 * the length of input data to consider are retrieved from the filter context.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003466 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003467__LJMP static int hlua_channel_get(lua_State *L)
3468{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003469 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003470 struct filter *filter;
3471 size_t offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003472 int ret;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003473
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003474 MAY_LJMP(check_args(L, 1, "get"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003475 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3476 if (IS_HTX_STRM(chn_strm(chn))) {
3477 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3478 WILL_LJMP(lua_error(L));
3479 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003480
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003481 offset = co_data(chn);
3482 len = ci_data(chn);
3483
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003484 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3485 if (filter && !hlua_filter_from_payload(filter))
3486 WILL_LJMP(lua_error(L));
3487
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003488 if (!ci_data(chn) && channel_input_closed(chn)) {
3489 lua_pushnil(L);
3490 return 1;
3491 }
3492
3493 ret = _hlua_channel_dup(chn, L, offset, len);
3494 _hlua_channel_delete(chn, offset, ret);
3495 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003496}
3497
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003498/* This functions consumes and returns one line. If the channel is closed,
3499 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003500 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003501 * value.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003502 *
3503 * From an action, All input data are considered. For a filter, the offset and
3504 * the length of input data to consider are retrieved from the filter context.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003505 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003506__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003507{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003508 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003509 struct filter *filter;
3510 size_t l, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003511 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003512
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003513 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003514
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003515 offset = co_data(chn);
3516 len = ci_data(chn);
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003517
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003518 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3519 if (filter && !hlua_filter_from_payload(filter))
3520 WILL_LJMP(lua_error(L));
3521
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003522 if (!ci_data(chn) && channel_input_closed(chn)) {
3523 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003524 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003525 }
3526
3527 for (l = 0; l < len; l++) {
3528 if (*(b_peek(&chn->buf, offset+l)) == '\n') {
3529 len = l+1;
3530 goto dup;
3531 }
3532 }
3533
3534 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3535 /* Yield waiting for more data */
3536 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
3537 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003538
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003539 dup:
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003540 ret = _hlua_channel_dup(chn, L, offset, len);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003541 _hlua_channel_delete(chn, offset, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003542 return 1;
3543}
3544
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003545/* [ DEPRECATED ]
3546 *
3547 * Check arguments for the function "hlua_channel_getline_yield".
3548 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003549__LJMP static int hlua_channel_getline(lua_State *L)
3550{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003551 struct channel *chn;
3552
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003553 MAY_LJMP(check_args(L, 1, "getline"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003554 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3555 if (IS_HTX_STRM(chn_strm(chn))) {
3556 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3557 WILL_LJMP(lua_error(L));
3558 }
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003559 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3560}
3561
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003562/* Retrieves a given amount of input data at the given offset. By default all
3563 * available input data are returned. The offset may be negactive to start from
3564 * the end of input data. The length may be -1 to set it to the maximum buffer
3565 * size.
3566 */
3567__LJMP static int hlua_channel_get_data(lua_State *L)
3568{
3569 struct channel *chn;
3570
3571 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3572 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
3573 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3574 if (IS_HTX_STRM(chn_strm(chn))) {
3575 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3576 WILL_LJMP(lua_error(L));
3577 }
3578 return MAY_LJMP(hlua_channel_get_data_yield(L, 0, 0));
3579}
3580
3581/* Retrieves a given amount of input data at the given offset. By default all
3582 * available input data are returned. The offset may be negactive to start from
3583 * the end of input data. The length may be -1 to set it to the maximum buffer
3584 * size.
3585 */
3586__LJMP static int hlua_channel_get_line(lua_State *L)
3587{
3588 struct channel *chn;
3589
3590 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3591 WILL_LJMP(luaL_error(L, "'line' expects at most 2 arguments"));
3592 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3593 if (IS_HTX_STRM(chn_strm(chn))) {
3594 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3595 WILL_LJMP(lua_error(L));
3596 }
3597 return MAY_LJMP(hlua_channel_get_line_yield(L, 0, 0));
3598}
3599
3600/* Appends a string into the input side of channel. It returns the length of the
3601 * written string, or -1 if the channel is closed or if the buffer size is too
3602 * little for the data. 0 may be returned if nothing is copied. This function
3603 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003604 *
3605 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003606 */
Christopher Faulet23976d92021-08-06 09:59:49 +02003607__LJMP static int hlua_channel_append(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003608{
Christopher Faulet23976d92021-08-06 09:59:49 +02003609 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003610 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003611 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003612 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003613 int ret;
Christopher Faulet23976d92021-08-06 09:59:49 +02003614
3615 MAY_LJMP(check_args(L, 2, "append"));
3616 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003617 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003618 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003619 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003620 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003621 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003622
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003623 offset = co_data(chn);
3624 len = ci_data(chn);
3625
3626 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3627 if (filter && !hlua_filter_from_payload(filter))
3628 WILL_LJMP(lua_error(L));
3629
3630 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3631 if (ret > 0 && filter) {
3632 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3633
3634 flt_update_offsets(filter, chn, ret);
3635 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3636 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003637 lua_pushinteger(L, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003638 return 1;
3639}
3640
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003641/* Prepends a string into the input side of channel. It returns the length of the
3642 * written string, or -1 if the channel is closed or if the buffer size is too
3643 * little for the data. 0 may be returned if nothing is copied. This function
3644 * does not yield.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003645 *
3646 * For a filter, the context is updated on success.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003647 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003648__LJMP static int hlua_channel_prepend(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003649{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003650 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003651 struct filter *filter;
Christopher Faulet23976d92021-08-06 09:59:49 +02003652 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003653 size_t sz, offset, len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003654 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003655
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003656 MAY_LJMP(check_args(L, 2, "prepend"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003657 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003658 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3659 if (IS_HTX_STRM(chn_strm(chn))) {
3660 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3661 WILL_LJMP(lua_error(L));
3662 }
3663
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003664 offset = co_data(chn);
3665 len = ci_data(chn);
3666
3667 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3668 if (filter && !hlua_filter_from_payload(filter))
3669 WILL_LJMP(lua_error(L));
3670
3671 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3672 if (ret > 0 && filter) {
3673 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3674
3675 flt_update_offsets(filter, chn, ret);
3676 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
3677 }
3678
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003679 lua_pushinteger(L, ret);
3680 return 1;
3681}
3682
3683/* Inserts a given amount of input data at the given offset by a string
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003684 * content. By default the string is appended in front of input data. It
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003685 * returns the length of the written string, or -1 if the channel is closed or
3686 * if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003687 *
3688 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003689 */
3690__LJMP static int hlua_channel_insert_data(lua_State *L)
3691{
3692 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003693 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003694 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003695 size_t sz, input, output;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003696 int ret, offset;
3697
3698 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
3699 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
3700 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3701 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003702
3703 output = co_data(chn);
3704 input = ci_data(chn);
3705
3706 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3707 if (filter && !hlua_filter_from_payload(filter))
3708 WILL_LJMP(lua_error(L));
3709
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003710 offset = output;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003711 if (lua_gettop(L) > 2) {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003712 offset = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003713 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003714 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003715 offset += output;
Aurelien DARRAGONafb7daf2022-10-04 12:16:05 +02003716 if (offset > output + input) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003717 lua_pushfstring(L, "offset out of range.");
3718 WILL_LJMP(lua_error(L));
3719 }
3720 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003721 if (IS_HTX_STRM(chn_strm(chn))) {
3722 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3723 WILL_LJMP(lua_error(L));
3724 }
3725
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003726 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3727 if (ret > 0 && filter) {
3728 struct hlua_flt_ctx *flt_ctx = filter->ctx;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003729
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003730 flt_update_offsets(filter, chn, ret);
3731 flt_ctx->cur_len[CHN_IDX(chn)] += ret;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003732 }
3733
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003734 lua_pushinteger(L, ret);
3735 return 1;
3736}
3737/* Replaces a given amount of input data at the given offset by a string
3738 * content. By default all remaining data are removed (offset = 0 and len =
3739 * -1). It returns the length of the written string, or -1 if the channel is
3740 * closed or if the buffer size is too little for the data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003741 *
3742 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003743 */
3744__LJMP static int hlua_channel_set_data(lua_State *L)
3745{
3746 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003747 struct filter *filter;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003748 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003749 size_t sz, input, output;
3750 int ret, offset, len;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003751
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003752 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
3753 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
3754 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3755 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003756
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003757 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003758 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003759 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003760 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003761
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003762 output = co_data(chn);
3763 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003764
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003765 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3766 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003767 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003768
3769 offset = output;
3770 if (lua_gettop(L) > 2) {
3771 offset = MAY_LJMP(luaL_checkinteger(L, 3));
3772 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003773 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003774 offset += output;
3775 if (offset < output || offset > input + output) {
3776 lua_pushfstring(L, "offset out of range.");
3777 WILL_LJMP(lua_error(L));
3778 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003779 }
3780
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003781 len = output + input - offset;
3782 if (lua_gettop(L) == 4) {
3783 len = MAY_LJMP(luaL_checkinteger(L, 4));
3784 if (!len)
3785 goto set;
3786 if (len == -1)
3787 len = output + input - offset;
3788 if (len < 0 || offset + len > output + input) {
3789 lua_pushfstring(L, "length out of range.");
3790 WILL_LJMP(lua_error(L));
3791 }
3792 }
3793
3794 set:
Christopher Faulet23976d92021-08-06 09:59:49 +02003795 /* Be sure we can copied the string once input data will be removed. */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003796 if (sz > c_room(chn) + len)
Christopher Faulet23976d92021-08-06 09:59:49 +02003797 lua_pushinteger(L, -1);
3798 else {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003799 _hlua_channel_delete(chn, offset, len);
3800 ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
3801 if (filter) {
3802 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3803
3804 len -= (ret > 0 ? ret : 0);
3805 flt_update_offsets(filter, chn, -len);
3806 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3807 }
3808
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003809 lua_pushinteger(L, ret);
Christopher Faulet23976d92021-08-06 09:59:49 +02003810 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003811 return 1;
3812}
3813
3814/* Removes a given amount of input data at the given offset. By default all
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003815 * input data are removed (offset = 0 and len = -1). It returns the amount of
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003816 * the removed data.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003817 *
3818 * For a filter, the context is updated on success.
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003819 */
3820__LJMP static int hlua_channel_del_data(lua_State *L)
3821{
3822 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003823 struct filter *filter;
3824 size_t input, output;
3825 int offset, len;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003826
3827 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3828 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
3829 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003830
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003831 if (IS_HTX_STRM(chn_strm(chn))) {
3832 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3833 WILL_LJMP(lua_error(L));
3834 }
3835
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003836 output = co_data(chn);
3837 input = ci_data(chn);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003838
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003839 filter = hlua_channel_filter(L, 1, chn, &output, &input);
3840 if (filter && !hlua_filter_from_payload(filter))
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003841 WILL_LJMP(lua_error(L));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003842
3843 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00003844 if (lua_gettop(L) > 1) {
3845 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003846 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02003847 offset = MAX(0, (int)input + offset);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003848 offset += output;
3849 if (offset < output || offset > input + output) {
3850 lua_pushfstring(L, "offset out of range.");
3851 WILL_LJMP(lua_error(L));
3852 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003853 }
3854
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003855 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00003856 if (lua_gettop(L) == 3) {
3857 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003858 if (!len)
3859 goto end;
3860 if (len == -1)
3861 len = output + input - offset;
3862 if (len < 0 || offset + len > output + input) {
3863 lua_pushfstring(L, "length out of range.");
3864 WILL_LJMP(lua_error(L));
3865 }
3866 }
3867
3868 _hlua_channel_delete(chn, offset, len);
3869 if (filter) {
3870 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3871
3872 flt_update_offsets(filter, chn, -len);
3873 flt_ctx->cur_len[CHN_IDX(chn)] -= len;
3874 }
3875
3876 end:
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003877 lua_pushinteger(L, len);
Christopher Faulet23976d92021-08-06 09:59:49 +02003878 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003879}
3880
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003881/* Append data in the output side of the buffer. This data is immediately
3882 * sent. The function returns the amount of data written. If the buffer
3883 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003884 * if the channel is closed.
3885 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003886__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003887{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003888 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003889 struct filter *filter;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003890 const char *str;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003891 size_t offset, len, sz;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003892 int l, ret;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003893 struct hlua *hlua;
3894
3895 /* Get hlua struct, or NULL if we execute from main lua state */
3896 hlua = hlua_gethlua(L);
3897 if (!hlua) {
3898 lua_pushnil(L);
3899 return 1;
3900 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003901
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003902 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3903 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3904 l = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003905
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003906 offset = co_data(chn);
3907 len = ci_data(chn);
3908
3909 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
3910 if (filter && !hlua_filter_from_payload(filter))
3911 WILL_LJMP(lua_error(L));
3912
3913
Willy Tarreau47860ed2015-03-10 14:07:50 +01003914 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003915 lua_pushinteger(L, -1);
3916 return 1;
3917 }
3918
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003919 len = c_room(chn);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003920 if (len > sz -l) {
3921 if (filter) {
3922 lua_pushinteger(L, -1);
3923 return 1;
3924 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003925 len = sz - l;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003926 }
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003927
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003928 ret = _hlua_channel_insert(chn, L, ist2(str, len), offset);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003929 if (ret == -1) {
3930 lua_pop(L, 1);
3931 lua_pushinteger(L, -1);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003932 return 1;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003933 }
3934 if (ret) {
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003935 if (filter) {
3936 struct hlua_flt_ctx *flt_ctx = filter->ctx;
3937
3938
3939 flt_update_offsets(filter, chn, ret);
3940 FLT_OFF(filter, chn) += ret;
3941 flt_ctx->cur_off[CHN_IDX(chn)] += ret;
3942 }
3943 else
3944 c_adv(chn, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003945
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003946 l += ret;
3947 lua_pop(L, 1);
3948 lua_pushinteger(L, l);
3949 }
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003950
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003951 if (l < sz) {
3952 /* Yield only if the channel's output is not empty.
3953 * Otherwise it means we cannot add more data. */
3954 if (co_data(chn) == 0 || HLUA_CANT_YIELD(hlua_gethlua(L)))
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003955 return 1;
3956
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003957 /* If we are waiting for space in the response buffer, we
3958 * must set the flag WAKERESWR. This flag required the task
3959 * wake up if any activity is detected on the response buffer.
3960 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003961 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003962 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003963 else
3964 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003965 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003966 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003967
3968 return 1;
3969}
3970
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003971/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003972 * yield the LUA process, and resume it without checking the
3973 * input arguments.
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02003974 *
3975 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003976 */
3977__LJMP static int hlua_channel_send(lua_State *L)
3978{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003979 struct channel *chn;
3980
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003981 MAY_LJMP(check_args(L, 2, "send"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003982 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3983 if (IS_HTX_STRM(chn_strm(chn))) {
3984 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3985 WILL_LJMP(lua_error(L));
3986 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003987 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003988 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003989}
3990
3991/* This function forward and amount of butes. The data pass from
3992 * the input side of the buffer to the output side, and can be
3993 * forwarded. This function never fails.
3994 *
3995 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003996 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003997 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003998__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003999{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004000 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004001 struct filter *filter;
4002 size_t offset, len, fwd;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004003 int l, max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01004004 struct hlua *hlua;
4005
4006 /* Get hlua struct, or NULL if we execute from main lua state */
4007 hlua = hlua_gethlua(L);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004008 if (!hlua) {
4009 lua_pushnil(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01004010 return 1;
Thierry Fournier77016da2020-08-15 14:35:51 +02004011 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01004012
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004013 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004014 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004015 l = MAY_LJMP(luaL_checkinteger(L, -1));
4016
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004017 offset = co_data(chn);
4018 len = ci_data(chn);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004019
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004020 filter = hlua_channel_filter(L, 1, chn, &offset, &len);
4021 if (filter && !hlua_filter_from_payload(filter))
4022 WILL_LJMP(lua_error(L));
4023
4024 max = fwd - l;
4025 if (max > len)
4026 max = len;
4027
4028 if (filter) {
4029 struct hlua_flt_ctx *flt_ctx = filter->ctx;
4030
4031 FLT_OFF(filter, chn) += max;
4032 flt_ctx->cur_off[CHN_IDX(chn)] += max;
4033 flt_ctx->cur_len[CHN_IDX(chn)] -= max;
4034 }
4035 else
4036 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004037
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004038 l += max;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004039 lua_pop(L, 1);
4040 lua_pushinteger(L, l);
4041
4042 /* Check if it miss bytes to forward. */
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004043 if (l < fwd) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004044 /* The the input channel or the output channel are closed, we
4045 * must return the amount of data forwarded.
4046 */
Christopher Faulet2e60aa42021-08-05 11:58:37 +02004047 if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L)))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004048 return 1;
4049
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004050 /* If we are waiting for space data in the response buffer, we
4051 * must set the flag WAKERESWR. This flag required the task
4052 * wake up if any activity is detected on the response buffer.
4053 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01004054 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004055 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01004056 else
4057 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01004058
Ilya Shipitsin4a689da2022-10-29 09:34:32 +05004059 /* Otherwise, we can yield waiting for new data in the input side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02004060 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004061 }
4062
4063 return 1;
4064}
4065
4066/* Just check the input and prepare the stack for the previous
4067 * function "hlua_channel_forward_yield"
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004068 *
4069 * This function cannot be called from a filter.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004070 */
4071__LJMP static int hlua_channel_forward(lua_State *L)
4072{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004073 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004074
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02004075 MAY_LJMP(check_args(L, 2, "forward"));
4076 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4077 if (IS_HTX_STRM(chn_strm(chn))) {
4078 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
4079 WILL_LJMP(lua_error(L));
4080 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004081 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01004082 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004083}
4084
4085/* Just returns the number of bytes available in the input
4086 * side of the buffer. This function never fails.
4087 */
4088__LJMP static int hlua_channel_get_in_len(lua_State *L)
4089{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004090 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004091 struct filter *filter;
4092 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004093
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004094 MAY_LJMP(check_args(L, 1, "input"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004095 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004096
4097 output = co_data(chn);
4098 input = ci_data(chn);
4099 filter = hlua_channel_filter(L, 1, chn, &output, &input);
4100 if (filter || !IS_HTX_STRM(chn_strm(chn)))
4101 lua_pushinteger(L, input);
4102 else {
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004103 struct htx *htx = htxbuf(&chn->buf);
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004104
Christopher Fauleta3ceac12018-12-14 13:39:09 +01004105 lua_pushinteger(L, htx->data - co_data(chn));
4106 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004107 return 1;
4108}
4109
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004110/* Returns true if the channel is full. */
4111__LJMP static int hlua_channel_is_full(lua_State *L)
4112{
4113 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004114
4115 MAY_LJMP(check_args(L, 1, "is_full"));
4116 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01004117 /* ignore the reserve, we are not on a producer side (ie in an
4118 * applet).
4119 */
4120 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01004121 return 1;
4122}
4123
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004124/* Returns true if the channel may still receive data. */
4125__LJMP static int hlua_channel_may_recv(lua_State *L)
4126{
4127 struct channel *chn;
4128
4129 MAY_LJMP(check_args(L, 1, "may_recv"));
4130 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4131 lua_pushboolean(L, (!channel_input_closed(chn) && channel_may_recv(chn)));
4132 return 1;
4133}
4134
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01004135/* Returns true if the channel is the response channel. */
4136__LJMP static int hlua_channel_is_resp(lua_State *L)
4137{
4138 struct channel *chn;
4139
4140 MAY_LJMP(check_args(L, 1, "is_resp"));
4141 chn = MAY_LJMP(hlua_checkchannel(L, 1));
4142
4143 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
4144 return 1;
4145}
4146
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004147/* Just returns the number of bytes available in the output
4148 * side of the buffer. This function never fails.
4149 */
4150__LJMP static int hlua_channel_get_out_len(lua_State *L)
4151{
Willy Tarreau47860ed2015-03-10 14:07:50 +01004152 struct channel *chn;
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004153 size_t output, input;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004154
Christopher Faulet6a79fc12021-08-06 16:02:36 +02004155 MAY_LJMP(check_args(L, 1, "output"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01004156 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta1ac5fb2021-08-09 10:22:46 +02004157
4158 output = co_data(chn);
4159 input = ci_data(chn);
4160 hlua_channel_filter(L, 1, chn, &output, &input);
4161
4162 lua_pushinteger(L, output);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004163 return 1;
4164}
4165
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004166/*
4167 *
4168 *
4169 * Class Fetches
4170 *
4171 *
4172 */
4173
4174/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004175 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004176 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004177__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004178{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004179 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004180}
4181
4182/* This function creates and push in the stack a fetch object according
4183 * with a current TXN.
4184 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004185static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004186{
Willy Tarreau7073c472015-04-06 11:15:40 +02004187 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004188
4189 /* Check stack size. */
4190 if (!lua_checkstack(L, 3))
4191 return 0;
4192
4193 /* Create the object: obj[0] = userdata.
4194 * Note that the base of the Fetches object is the
4195 * transaction object.
4196 */
4197 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004198 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004199 lua_rawseti(L, -2, 0);
4200
Willy Tarreau7073c472015-04-06 11:15:40 +02004201 hsmp->s = txn->s;
4202 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004203 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004204 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004205
4206 /* Pop a class sesison metatable and affect it to the userdata. */
4207 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
4208 lua_setmetatable(L, -2);
4209
4210 return 1;
4211}
4212
4213/* This function is an LUA binding. It is called with each sample-fetch.
4214 * It uses closure argument to store the associated sample-fetch. It
4215 * returns only one argument or throws an error. An error is thrown
4216 * only if an error is encountered during the argument parsing. If
4217 * the "sample-fetch" function fails, nil is returned.
4218 */
4219__LJMP static int hlua_run_sample_fetch(lua_State *L)
4220{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004221 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01004222 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004223 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004224 int i;
4225 struct sample smp;
4226
4227 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004228 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004229
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004230 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004231 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004232
Thierry FOURNIERca988662015-12-20 18:43:03 +01004233 /* Check execution authorization. */
4234 if (f->use & SMP_USE_HTTP_ANY &&
4235 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
4236 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
4237 "is not available in Lua services", f->kw);
4238 WILL_LJMP(lua_error(L));
4239 }
4240
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004241 /* Get extra arguments. */
4242 for (i = 0; i < lua_gettop(L) - 1; i++) {
4243 if (i >= ARGM_NBARGS)
4244 break;
4245 hlua_lua2arg(L, i + 2, &args[i]);
4246 }
4247 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004248 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004249
4250 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02004251 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004252
4253 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01004254 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004255 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004256 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004257 }
4258
4259 /* Initialise the sample. */
4260 memset(&smp, 0, sizeof(smp));
4261
4262 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01004263 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02004264 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004265 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004266 lua_pushstring(L, "");
4267 else
4268 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004269 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004270 }
4271
4272 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004273 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004274 hlua_smp2lua_str(L, &smp);
4275 else
4276 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004277
4278 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004279 free_args(args);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004280 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004281
4282 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004283 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004284 WILL_LJMP(lua_error(L));
4285 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01004286}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01004287
4288/*
4289 *
4290 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004291 * Class Converters
4292 *
4293 *
4294 */
4295
4296/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004297 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004298 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004299__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004300{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004301 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004302}
4303
4304/* This function creates and push in the stack a Converters object
4305 * according with a current TXN.
4306 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004307static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004308{
Willy Tarreau7073c472015-04-06 11:15:40 +02004309 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004310
4311 /* Check stack size. */
4312 if (!lua_checkstack(L, 3))
4313 return 0;
4314
4315 /* Create the object: obj[0] = userdata.
4316 * Note that the base of the Converters object is the
4317 * same than the TXN object.
4318 */
4319 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02004320 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004321 lua_rawseti(L, -2, 0);
4322
Willy Tarreau7073c472015-04-06 11:15:40 +02004323 hsmp->s = txn->s;
4324 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01004325 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004326 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004327
Willy Tarreau87b09662015-04-03 00:22:06 +02004328 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004329 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
4330 lua_setmetatable(L, -2);
4331
4332 return 1;
4333}
4334
4335/* This function is an LUA binding. It is called with each converter.
4336 * It uses closure argument to store the associated converter. It
4337 * returns only one argument or throws an error. An error is thrown
4338 * only if an error is encountered during the argument parsing. If
4339 * the converter function function fails, nil is returned.
4340 */
4341__LJMP static int hlua_run_sample_conv(lua_State *L)
4342{
Willy Tarreauda5f1082015-04-06 11:17:13 +02004343 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004344 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02004345 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004346 int i;
4347 struct sample smp;
4348
4349 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004350 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004351
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004352 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004353 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004354
4355 /* Get extra arguments. */
4356 for (i = 0; i < lua_gettop(L) - 2; i++) {
4357 if (i >= ARGM_NBARGS)
4358 break;
4359 hlua_lua2arg(L, i + 3, &args[i]);
4360 }
4361 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004362 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004363
4364 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02004365 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004366
4367 /* Run the special args checker. */
4368 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
4369 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004370 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004371 }
4372
4373 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004374 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004375 if (!hlua_lua2smp(L, 2, &smp)) {
4376 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004377 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004378 }
4379
Willy Tarreau1777ea62016-03-10 16:15:46 +01004380 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
4381
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004382 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004383 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004384 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004385 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004386 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004387 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02004388 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
4389 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004390 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004391 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004392 }
4393
4394 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02004395 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004396 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004397 lua_pushstring(L, "");
4398 else
Willy Tarreaua678b432015-08-28 10:14:59 +02004399 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004400 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004401 }
4402
4403 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004404 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01004405 hlua_smp2lua_str(L, &smp);
4406 else
4407 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004408 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004409 free_args(args);
Willy Tarreaua678b432015-08-28 10:14:59 +02004410 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004411
4412 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02004413 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02004414 WILL_LJMP(lua_error(L));
4415 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004416}
4417
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004418/*
4419 *
4420 *
4421 * Class AppletTCP
4422 *
4423 *
4424 */
4425
4426/* Returns a struct hlua_txn if the stack entry "ud" is
4427 * a class stream, otherwise it throws an error.
4428 */
4429__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
4430{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004431 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004432}
4433
4434/* This function creates and push in the stack an Applet object
4435 * according with a current TXN.
4436 */
4437static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
4438{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004439 struct hlua_appctx *luactx;
Willy Tarreau0698c802022-05-11 14:09:57 +02004440 struct stream *s = appctx_strm(ctx);
Christopher Faulet2da02ae2022-02-24 13:45:27 +01004441 struct proxy *p;
4442
4443 ALREADY_CHECKED(s);
4444 p = s->be;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004445
4446 /* Check stack size. */
4447 if (!lua_checkstack(L, 3))
4448 return 0;
4449
4450 /* Create the object: obj[0] = userdata.
4451 * Note that the base of the Converters object is the
4452 * same than the TXN object.
4453 */
4454 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004455 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004456 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004457 luactx->appctx = ctx;
4458 luactx->htxn.s = s;
4459 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004460
4461 /* Create the "f" field that contains a list of fetches. */
4462 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004463 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004464 return 0;
4465 lua_settable(L, -3);
4466
4467 /* Create the "sf" field that contains a list of stringsafe fetches. */
4468 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004469 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004470 return 0;
4471 lua_settable(L, -3);
4472
4473 /* Create the "c" field that contains a list of converters. */
4474 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004475 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004476 return 0;
4477 lua_settable(L, -3);
4478
4479 /* Create the "sc" field that contains a list of stringsafe converters. */
4480 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004481 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004482 return 0;
4483 lua_settable(L, -3);
4484
4485 /* Pop a class stream metatable and affect it to the table. */
4486 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
4487 lua_setmetatable(L, -2);
4488
4489 return 1;
4490}
4491
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004492__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
4493{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004494 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004495 struct stream *s;
4496 const char *name;
4497 size_t len;
4498 struct sample smp;
4499
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004500 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4501 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004502
4503 /* It is useles to retrieve the stream, but this function
4504 * runs only in a stream context.
4505 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004506 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004507 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004508 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004509
4510 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004511 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004512 hlua_lua2smp(L, 3, &smp);
4513
4514 /* Store the sample in a variable. */
4515 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004516
4517 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4518 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4519 else
4520 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4521
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004522 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004523}
4524
4525__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
4526{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004527 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004528 struct stream *s;
4529 const char *name;
4530 size_t len;
4531 struct sample smp;
4532
4533 MAY_LJMP(check_args(L, 2, "unset_var"));
4534
4535 /* It is useles to retrieve the stream, but this function
4536 * runs only in a stream context.
4537 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004538 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004539 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004540 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004541
4542 /* Unset the variable. */
4543 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004544 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4545 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004546}
4547
4548__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
4549{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004550 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004551 struct stream *s;
4552 const char *name;
4553 size_t len;
4554 struct sample smp;
4555
4556 MAY_LJMP(check_args(L, 2, "get_var"));
4557
4558 /* It is useles to retrieve the stream, but this function
4559 * runs only in a stream context.
4560 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004561 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004562 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004563 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004564
4565 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02004566 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004567 lua_pushnil(L);
4568 return 1;
4569 }
4570
4571 return hlua_smp2lua(L, &smp);
4572}
4573
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004574__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
4575{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004576 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4577 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004578 struct hlua *hlua;
4579
4580 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004581 if (!s->hlua)
4582 return 0;
4583 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004584
4585 MAY_LJMP(check_args(L, 2, "set_priv"));
4586
4587 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004588 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004589
4590 /* Get and store new value. */
4591 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4592 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4593
4594 return 0;
4595}
4596
4597__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
4598{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004599 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4600 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004601 struct hlua *hlua;
4602
4603 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004604 if (!s->hlua) {
4605 lua_pushnil(L);
4606 return 1;
4607 }
4608 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004609
4610 /* Push configuration index in the stack. */
4611 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4612
4613 return 1;
4614}
4615
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004616/* If expected data not yet available, it returns a yield. This function
4617 * consumes the data in the buffer. It returns a string containing the
4618 * data. This string can be empty.
4619 */
4620__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
4621{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004622 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004623 struct stconn *sc = appctx_sc(luactx->appctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004624 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004625 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004626 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004627 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004628 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004629
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004630 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004631 ret = co_getline_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004632
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004633 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004634 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004635 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004636 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004637 }
4638
4639 /* End of data: commit the total strings and return. */
4640 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004641 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004642 return 1;
4643 }
4644
4645 /* Ensure that the block 2 length is usable. */
4646 if (ret == 1)
4647 len2 = 0;
4648
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004649 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004650 luaL_addlstring(&luactx->b, blk1, len1);
4651 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004652
4653 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004654 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004655 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004656 return 1;
4657}
4658
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004659/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004660__LJMP static int hlua_applet_tcp_getline(lua_State *L)
4661{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004662 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004663
4664 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004665 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004666
4667 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
4668}
4669
4670/* If expected data not yet available, it returns a yield. This function
4671 * consumes the data in the buffer. It returns a string containing the
4672 * data. This string can be empty.
4673 */
4674__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
4675{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004676 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004677 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004678 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004679 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004680 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004681 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004682 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004683 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004684
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004685 /* Read the maximum amount of data available. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004686 ret = co_getblk_nc(sc_oc(sc), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004687
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004688 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004689 if (ret == 0) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02004690 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004691 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004692 }
4693
4694 /* End of data: commit the total strings and return. */
4695 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004696 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004697 return 1;
4698 }
4699
4700 /* Ensure that the block 2 length is usable. */
4701 if (ret == 1)
4702 len2 = 0;
4703
4704 if (len == -1) {
4705
4706 /* If len == -1, catenate all the data avalaile and
4707 * yield because we want to get all the data until
4708 * the end of data stream.
4709 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004710 luaL_addlstring(&luactx->b, blk1, len1);
4711 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004712 co_skip(sc_oc(sc), len1 + len2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004713 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004714 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004715
4716 } else {
4717
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004718 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004719 if (len1 > len)
4720 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004721 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004722 len -= len1;
4723
4724 /* Copy the second block. */
4725 if (len2 > len)
4726 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004727 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004728 len -= len2;
4729
4730 /* Consume input channel output buffer data. */
Willy Tarreau3e7be362022-05-27 10:35:27 +02004731 co_skip(sc_oc(sc), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004732
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004733 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004734 if (len > 0) {
4735 lua_pushinteger(L, len);
4736 lua_replace(L, 2);
Willy Tarreau90e8b452022-05-25 18:21:43 +02004737 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02004738 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004739 }
4740
4741 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004742 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004743 return 1;
4744 }
4745
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004746 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004747 hlua_pusherror(L, "Lua: internal error");
4748 WILL_LJMP(lua_error(L));
4749 return 0;
4750}
4751
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004752/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004753__LJMP static int hlua_applet_tcp_recv(lua_State *L)
4754{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004755 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004756 int len = -1;
4757
4758 if (lua_gettop(L) > 2)
4759 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4760 if (lua_gettop(L) >= 2) {
4761 len = MAY_LJMP(luaL_checkinteger(L, 2));
4762 lua_pop(L, 1);
4763 }
4764
4765 /* Confirm or set the required length */
4766 lua_pushinteger(L, len);
4767
4768 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004769 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004770
4771 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
4772}
4773
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004774/* Append data in the output side of the buffer. This data is immediately
4775 * sent. The function returns the amount of data written. If the buffer
4776 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004777 * if the channel is closed.
4778 */
4779__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4780{
4781 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004782 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004783 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4784 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreauc12b3212022-05-27 11:08:15 +02004785 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02004786 struct channel *chn = sc_ic(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004787 int max;
4788
4789 /* Get the max amount of data which can write as input in the channel. */
4790 max = channel_recv_max(chn);
4791 if (max > (len - l))
4792 max = len - l;
4793
4794 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004795 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004796
4797 /* update counters. */
4798 l += max;
4799 lua_pop(L, 1);
4800 lua_pushinteger(L, l);
4801
4802 /* If some data is not send, declares the situation to the
4803 * applet, and returns a yield.
4804 */
4805 if (l < len) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02004806 sc_need_room(sc);
Willy Tarreau9635e032018-10-16 17:52:55 +02004807 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004808 }
4809
4810 return 1;
4811}
4812
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004813/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004814 * yield the LUA process, and resume it without checking the
4815 * input arguments.
4816 */
4817__LJMP static int hlua_applet_tcp_send(lua_State *L)
4818{
4819 MAY_LJMP(check_args(L, 2, "send"));
4820 lua_pushinteger(L, 0);
4821
4822 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
4823}
4824
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004825/*
4826 *
4827 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004828 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004829 *
4830 *
4831 */
4832
4833/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004834 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004835 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004836__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004837{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004838 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004839}
4840
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004841/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004842 * according with a current TXN.
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004843 * It relies on the caller to have already reserved the room in ctx->svcctx
4844 * for the local storage of hlua_http_ctx.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004845 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004846static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004847{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004848 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004849 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01004850 struct hlua_txn htxn;
Willy Tarreau0698c802022-05-11 14:09:57 +02004851 struct stream *s = appctx_strm(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004852 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02004853 struct htx *htx;
4854 struct htx_blk *blk;
4855 struct htx_sl *sl;
4856 struct ist path;
4857 unsigned long long len = 0;
4858 int32_t pos;
Amaury Denoyellec453f952021-07-06 11:40:12 +02004859 struct http_uri_parser parser;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004860
4861 /* Check stack size. */
4862 if (!lua_checkstack(L, 3))
4863 return 0;
4864
4865 /* Create the object: obj[0] = userdata.
4866 * Note that the base of the Converters object is the
4867 * same than the TXN object.
4868 */
4869 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004870 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004871 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004872 luactx->appctx = ctx;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02004873 http_ctx->status = 200; /* Default status code returned. */
4874 http_ctx->reason = NULL; /* Use default reason based on status */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004875 luactx->htxn.s = s;
4876 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004877
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004878 /* Create the "f" field that contains a list of fetches. */
4879 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004880 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004881 return 0;
4882 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004883
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004884 /* Create the "sf" field that contains a list of stringsafe fetches. */
4885 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004886 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004887 return 0;
4888 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004889
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004890 /* Create the "c" field that contains a list of converters. */
4891 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004892 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004893 return 0;
4894 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004895
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004896 /* Create the "sc" field that contains a list of stringsafe converters. */
4897 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004898 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004899 return 0;
4900 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004901
Christopher Fauleta2097962019-07-15 16:25:33 +02004902 htx = htxbuf(&s->req.buf);
4903 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004904 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004905 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004906
Christopher Fauleta2097962019-07-15 16:25:33 +02004907 /* Stores the request method. */
4908 lua_pushstring(L, "method");
4909 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4910 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004911
Christopher Fauleta2097962019-07-15 16:25:33 +02004912 /* Stores the http version. */
4913 lua_pushstring(L, "version");
4914 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4915 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004916
Christopher Fauleta2097962019-07-15 16:25:33 +02004917 /* creates an array of headers. hlua_http_get_headers() crates and push
4918 * the array on the top of the stack.
4919 */
4920 lua_pushstring(L, "headers");
4921 htxn.s = s;
4922 htxn.p = px;
4923 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004924 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004925 return 0;
4926 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004927
Amaury Denoyellec453f952021-07-06 11:40:12 +02004928 parser = http_uri_parser_init(htx_sl_req_uri(sl));
4929 path = http_parse_path(&parser);
Tim Duesterhused526372020-03-05 17:56:33 +01004930 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004931 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004932
Christopher Fauleta2097962019-07-15 16:25:33 +02004933 p = path.ptr;
Tim Duesterhus4c8f75f2021-11-06 15:14:44 +01004934 end = istend(path);
Christopher Fauleta2097962019-07-15 16:25:33 +02004935 q = p;
4936 while (q < end && *q != '?')
4937 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004938
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004939 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004940 lua_pushstring(L, "path");
4941 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004942 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004943
Christopher Fauleta2097962019-07-15 16:25:33 +02004944 /* Stores the query string. */
4945 lua_pushstring(L, "qs");
4946 if (*q == '?')
4947 q++;
4948 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004949 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004950 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004951
Christopher Fauleta2097962019-07-15 16:25:33 +02004952 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4953 struct htx_blk *blk = htx_get_blk(htx, pos);
4954 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004955
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004956 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02004957 break;
4958 if (type == HTX_BLK_DATA)
4959 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004960 }
Christopher Faulet2e47e3a2023-01-13 11:40:24 +01004961 if (htx->extra != HTX_UNKOWN_PAYLOAD_LENGTH)
Christopher Fauleta2097962019-07-15 16:25:33 +02004962 len += htx->extra;
4963
4964 /* Stores the request path. */
4965 lua_pushstring(L, "length");
4966 lua_pushinteger(L, len);
4967 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004968
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004969 /* Create an empty array of HTTP request headers. */
4970 lua_pushstring(L, "response");
4971 lua_newtable(L);
4972 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004973
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004974 /* Pop a class stream metatable and affect it to the table. */
4975 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4976 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004977
4978 return 1;
4979}
4980
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004981__LJMP static int hlua_applet_http_set_var(lua_State *L)
4982{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004983 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004984 struct stream *s;
4985 const char *name;
4986 size_t len;
4987 struct sample smp;
4988
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004989 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4990 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004991
4992 /* It is useles to retrieve the stream, but this function
4993 * runs only in a stream context.
4994 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004995 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004996 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004997 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004998
4999 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01005000 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005001 hlua_lua2smp(L, 3, &smp);
5002
5003 /* Store the sample in a variable. */
5004 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005005
5006 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
5007 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
5008 else
5009 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
5010
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005011 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005012}
5013
5014__LJMP static int hlua_applet_http_unset_var(lua_State *L)
5015{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005016 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005017 struct stream *s;
5018 const char *name;
5019 size_t len;
5020 struct sample smp;
5021
5022 MAY_LJMP(check_args(L, 2, "unset_var"));
5023
5024 /* It is useles to retrieve the stream, but this function
5025 * runs only in a stream context.
5026 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005027 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005028 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02005029 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005030
5031 /* Unset the variable. */
5032 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005033 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
5034 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005035}
5036
5037__LJMP static int hlua_applet_http_get_var(lua_State *L)
5038{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005039 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005040 struct stream *s;
5041 const char *name;
5042 size_t len;
5043 struct sample smp;
5044
5045 MAY_LJMP(check_args(L, 2, "get_var"));
5046
5047 /* It is useles to retrieve the stream, but this function
5048 * runs only in a stream context.
5049 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005050 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005051 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02005052 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005053
5054 smp_set_owner(&smp, s->be, s->sess, s, 0);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02005055 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01005056 lua_pushnil(L);
5057 return 1;
5058 }
5059
5060 return hlua_smp2lua(L, &smp);
5061}
5062
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005063__LJMP static int hlua_applet_http_set_priv(lua_State *L)
5064{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005065 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5066 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005067 struct hlua *hlua;
5068
5069 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005070 if (!s->hlua)
5071 return 0;
5072 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005073
5074 MAY_LJMP(check_args(L, 2, "set_priv"));
5075
5076 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005077 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005078
5079 /* Get and store new value. */
5080 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5081 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5082
5083 return 0;
5084}
5085
5086__LJMP static int hlua_applet_http_get_priv(lua_State *L)
5087{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005088 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5089 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01005090 struct hlua *hlua;
5091
5092 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01005093 if (!s->hlua) {
5094 lua_pushnil(L);
5095 return 1;
5096 }
5097 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01005098
5099 /* Push configuration index in the stack. */
5100 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5101
5102 return 1;
5103}
5104
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005105/* If expected data not yet available, it returns a yield. This function
5106 * consumes the data in the buffer. It returns a string containing the
5107 * data. This string can be empty.
5108 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005109__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005110{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005111 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005112 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005113 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005114 struct htx *htx;
5115 struct htx_blk *blk;
5116 size_t count;
5117 int stop = 0;
5118
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005119 htx = htx_from_buf(&req->buf);
5120 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02005121 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01005122
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005123 while (count && !stop && blk) {
5124 enum htx_blk_type type = htx_get_blk_type(blk);
5125 uint32_t sz = htx_get_blksz(blk);
5126 struct ist v;
5127 uint32_t vlen;
5128 char *nl;
5129
5130 vlen = sz;
5131 if (vlen > count) {
5132 if (type != HTX_BLK_DATA)
5133 break;
5134 vlen = count;
5135 }
5136
5137 switch (type) {
5138 case HTX_BLK_UNUSED:
5139 break;
5140
5141 case HTX_BLK_DATA:
5142 v = htx_get_blk_value(htx, blk);
5143 v.len = vlen;
5144 nl = istchr(v, '\n');
5145 if (nl != NULL) {
5146 stop = 1;
5147 vlen = nl - v.ptr + 1;
5148 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02005149 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005150 break;
5151
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005152 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005153 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005154 stop = 1;
5155 break;
5156
5157 default:
5158 break;
5159 }
5160
Willy Tarreau84240042022-02-28 16:51:23 +01005161 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005162 count -= vlen;
5163 if (sz == vlen)
5164 blk = htx_remove_blk(htx, blk);
5165 else {
5166 htx_cut_data_blk(htx, blk, vlen);
5167 break;
5168 }
5169 }
5170
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005171 /* The message was fully consumed and no more data are expected
5172 * (EOM flag set).
5173 */
Christopher Faulet904763f2023-03-22 14:53:11 +01005174 if (htx_is_empty(htx) && (sc->flags & SC_FL_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005175 stop = 1;
5176
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005177 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005178 if (!stop) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02005179 applet_need_more_data(luactx->appctx);
Christopher Fauleta2097962019-07-15 16:25:33 +02005180 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005181 }
5182
5183 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005184 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005185 return 1;
5186}
5187
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005188
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005189/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005190__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005191{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005192 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005193
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005194 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005195 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005196
Christopher Fauleta2097962019-07-15 16:25:33 +02005197 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005198}
5199
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005200/* If expected data not yet available, it returns a yield. This function
5201 * consumes the data in the buffer. It returns a string containing the
5202 * data. This string can be empty.
5203 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005204__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005205{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005206 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005207 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005208 struct channel *req = sc_oc(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005209 struct htx *htx;
5210 struct htx_blk *blk;
5211 size_t count;
5212 int len;
5213
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005214 htx = htx_from_buf(&req->buf);
5215 len = MAY_LJMP(luaL_checkinteger(L, 2));
5216 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02005217 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005218 while (count && len && blk) {
5219 enum htx_blk_type type = htx_get_blk_type(blk);
5220 uint32_t sz = htx_get_blksz(blk);
5221 struct ist v;
5222 uint32_t vlen;
5223
5224 vlen = sz;
5225 if (len > 0 && vlen > len)
5226 vlen = len;
5227 if (vlen > count) {
5228 if (type != HTX_BLK_DATA)
5229 break;
5230 vlen = count;
5231 }
5232
5233 switch (type) {
5234 case HTX_BLK_UNUSED:
5235 break;
5236
5237 case HTX_BLK_DATA:
5238 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02005239 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005240 break;
5241
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005242 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005243 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005244 len = 0;
5245 break;
5246
5247 default:
5248 break;
5249 }
5250
Willy Tarreau84240042022-02-28 16:51:23 +01005251 c_rew(req, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005252 count -= vlen;
5253 if (len > 0)
5254 len -= vlen;
5255 if (sz == vlen)
5256 blk = htx_remove_blk(htx, blk);
5257 else {
5258 htx_cut_data_blk(htx, blk, vlen);
5259 break;
5260 }
5261 }
5262
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005263 /* The message was fully consumed and no more data are expected
5264 * (EOM flag set).
5265 */
Christopher Faulet904763f2023-03-22 14:53:11 +01005266 if (htx_is_empty(htx) && (sc->flags & SC_FL_EOI))
Christopher Fauleteccb31c2021-04-02 14:24:56 +02005267 len = 0;
5268
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005269 htx_to_buf(htx, &req->buf);
5270
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005271 /* If we are no other data available, yield waiting for new data. */
5272 if (len) {
5273 if (len > 0) {
5274 lua_pushinteger(L, len);
5275 lua_replace(L, 2);
5276 }
Willy Tarreau90e8b452022-05-25 18:21:43 +02005277 applet_need_more_data(luactx->appctx);
Willy Tarreau9635e032018-10-16 17:52:55 +02005278 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005279 }
5280
5281 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005282 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005283 return 1;
5284}
5285
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005286/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005287__LJMP static int hlua_applet_http_recv(lua_State *L)
5288{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005289 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005290 int len = -1;
5291
5292 /* Check arguments. */
5293 if (lua_gettop(L) > 2)
5294 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
5295 if (lua_gettop(L) >= 2) {
5296 len = MAY_LJMP(luaL_checkinteger(L, 2));
5297 lua_pop(L, 1);
5298 }
5299
Christopher Fauleta2097962019-07-15 16:25:33 +02005300 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005301
Christopher Fauleta2097962019-07-15 16:25:33 +02005302 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005303 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005304
Christopher Fauleta2097962019-07-15 16:25:33 +02005305 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005306}
5307
5308/* Append data in the output side of the buffer. This data is immediately
5309 * sent. The function returns the amount of data written. If the buffer
5310 * cannot contain the data, the function yields. The function returns -1
5311 * if the channel is closed.
5312 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005313__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005314{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005315 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005316 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005317 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005318 struct htx *htx = htx_from_buf(&res->buf);
5319 const char *data;
5320 size_t len;
5321 int l = MAY_LJMP(luaL_checkinteger(L, 3));
5322 int max;
5323
Christopher Faulet9060fc02019-07-03 11:39:30 +02005324 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005325 if (!max)
5326 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005327
5328 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
5329
5330 /* Get the max amount of data which can write as input in the channel. */
5331 if (max > (len - l))
5332 max = len - l;
5333
5334 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02005335 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005336 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005337
5338 /* update counters. */
5339 l += max;
5340 lua_pop(L, 1);
5341 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005342
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005343 /* If some data is not send, declares the situation to the
5344 * applet, and returns a yield.
5345 */
5346 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01005347 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01005348 htx_to_buf(htx, &res->buf);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005349 sc_need_room(sc);
Willy Tarreau9635e032018-10-16 17:52:55 +02005350 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005351 }
5352
Christopher Fauleta2097962019-07-15 16:25:33 +02005353 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005354 return 1;
5355}
5356
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005357/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005358 * yield the LUA process, and resume it without checking the
5359 * input arguments.
5360 */
5361__LJMP static int hlua_applet_http_send(lua_State *L)
5362{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005363 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005364 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005365
5366 /* We want to send some data. Headers must be sent. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005367 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005368 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
5369 WILL_LJMP(lua_error(L));
5370 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005371
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005372 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02005373 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005374
Christopher Fauleta2097962019-07-15 16:25:33 +02005375 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005376}
5377
5378__LJMP static int hlua_applet_http_addheader(lua_State *L)
5379{
5380 const char *name;
5381 int ret;
5382
5383 MAY_LJMP(hlua_checkapplet_http(L, 1));
5384 name = MAY_LJMP(luaL_checkstring(L, 2));
5385 MAY_LJMP(luaL_checkstring(L, 3));
5386
5387 /* Push in the stack the "response" entry. */
5388 ret = lua_getfield(L, 1, "response");
5389 if (ret != LUA_TTABLE) {
5390 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
5391 "is expected as an array. %s found", lua_typename(L, ret));
5392 WILL_LJMP(lua_error(L));
5393 }
5394
5395 /* check if the header is already registered if it is not
5396 * the case, register it.
5397 */
5398 ret = lua_getfield(L, -1, name);
5399 if (ret == LUA_TNIL) {
5400
5401 /* Entry not found. */
5402 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
5403
5404 /* Insert the new header name in the array in the top of the stack.
5405 * It left the new array in the top of the stack.
5406 */
5407 lua_newtable(L);
5408 lua_pushvalue(L, 2);
5409 lua_pushvalue(L, -2);
5410 lua_settable(L, -4);
5411
5412 } else if (ret != LUA_TTABLE) {
5413
5414 /* corruption error. */
5415 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
5416 "is expected as an array. %s found", name, lua_typename(L, ret));
5417 WILL_LJMP(lua_error(L));
5418 }
5419
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005420 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005421 * the header value as new entry.
5422 */
5423 lua_pushvalue(L, 3);
5424 ret = lua_rawlen(L, -2);
5425 lua_rawseti(L, -2, ret + 1);
5426 lua_pushboolean(L, 1);
5427 return 1;
5428}
5429
5430__LJMP static int hlua_applet_http_status(lua_State *L)
5431{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005432 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005433 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005434 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005435 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005436
5437 if (status < 100 || status > 599) {
5438 lua_pushboolean(L, 0);
5439 return 1;
5440 }
5441
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005442 http_ctx->status = status;
5443 http_ctx->reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005444 lua_pushboolean(L, 1);
5445 return 1;
5446}
5447
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005448
Christopher Fauleta2097962019-07-15 16:25:33 +02005449__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005450{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005451 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005452 struct hlua_http_ctx *http_ctx = luactx->appctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02005453 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005454 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005455 struct htx *htx;
5456 struct htx_sl *sl;
5457 struct h1m h1m;
5458 const char *status, *reason;
5459 const char *name, *value;
5460 size_t nlen, vlen;
5461 unsigned int flags;
5462
5463 /* Send the message at once. */
5464 htx = htx_from_buf(&res->buf);
5465 h1m_init_res(&h1m);
5466
5467 /* Use the same http version than the request. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005468 status = ultoa_r(http_ctx->status, trash.area, trash.size);
5469 reason = http_ctx->reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005470 if (reason == NULL)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005471 reason = http_get_reason(http_ctx->status);
5472 if (http_ctx->flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005473 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5474 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
5475 }
5476 else {
5477 flags = HTX_SL_F_IS_RESP;
5478 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
5479 }
5480 if (!sl) {
5481 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005482 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005483 WILL_LJMP(lua_error(L));
5484 }
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005485 sl->info.res.status = http_ctx->status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005486
5487 /* Get the array associated to the field "response" in the object AppletHTTP. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005488 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
5489 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005490 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005491 WILL_LJMP(lua_error(L));
5492 }
5493
5494 /* Browse the list of headers. */
5495 lua_pushnil(L);
5496 while(lua_next(L, -2) != 0) {
5497 /* We expect a string as -2. */
5498 if (lua_type(L, -2) != LUA_TSTRING) {
5499 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005500 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005501 lua_typename(L, lua_type(L, -2)));
5502 WILL_LJMP(lua_error(L));
5503 }
5504 name = lua_tolstring(L, -2, &nlen);
5505
5506 /* We expect an array as -1. */
5507 if (lua_type(L, -1) != LUA_TTABLE) {
5508 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 +02005509 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005510 name,
5511 lua_typename(L, lua_type(L, -1)));
5512 WILL_LJMP(lua_error(L));
5513 }
5514
5515 /* Browse the table who is on the top of the stack. */
5516 lua_pushnil(L);
5517 while(lua_next(L, -2) != 0) {
5518 int id;
5519
5520 /* We expect a number as -2. */
5521 if (lua_type(L, -2) != LUA_TNUMBER) {
5522 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 +02005523 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005524 name,
5525 lua_typename(L, lua_type(L, -2)));
5526 WILL_LJMP(lua_error(L));
5527 }
5528 id = lua_tointeger(L, -2);
5529
5530 /* We expect a string as -2. */
5531 if (lua_type(L, -1) != LUA_TSTRING) {
5532 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 +02005533 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005534 name, id,
5535 lua_typename(L, lua_type(L, -1)));
5536 WILL_LJMP(lua_error(L));
5537 }
5538 value = lua_tolstring(L, -1, &vlen);
5539
5540 /* Simple Protocol checks. */
Christopher Faulet545fbba2021-09-28 09:36:25 +02005541 if (isteqi(ist2(name, nlen), ist("transfer-encoding"))) {
5542 int ret;
5543
5544 ret = h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
5545 if (ret < 0) {
5546 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
5547 luactx->appctx->rule->arg.hlua_rule->fcn->name,
5548 name);
5549 WILL_LJMP(lua_error(L));
5550 }
5551 else if (ret == 0)
5552 goto next; /* Skip it */
5553 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005554 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
5555 struct ist v = ist2(value, vlen);
5556 int ret;
5557
5558 ret = h1_parse_cont_len_header(&h1m, &v);
5559 if (ret < 0) {
5560 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005561 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005562 name);
5563 WILL_LJMP(lua_error(L));
5564 }
5565 else if (ret == 0)
5566 goto next; /* Skip it */
5567 }
5568
5569 /* Add a new header */
5570 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
5571 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005572 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005573 name);
5574 WILL_LJMP(lua_error(L));
5575 }
5576 next:
5577 /* Remove the array from the stack, and get next element with a remaining string. */
5578 lua_pop(L, 1);
5579 }
5580
5581 /* Remove the array from the stack, and get next element with a remaining string. */
5582 lua_pop(L, 1);
5583 }
5584
5585 if (h1m.flags & H1_MF_CHNK)
5586 h1m.flags &= ~H1_MF_CLEN;
5587 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5588 h1m.flags |= H1_MF_XFER_LEN;
5589
5590 /* Uset HTX start-line flags */
5591 if (h1m.flags & H1_MF_XFER_ENC)
5592 flags |= HTX_SL_F_XFER_ENC;
5593 if (h1m.flags & H1_MF_XFER_LEN) {
5594 flags |= HTX_SL_F_XFER_LEN;
5595 if (h1m.flags & H1_MF_CHNK)
5596 flags |= HTX_SL_F_CHNK;
5597 else if (h1m.flags & H1_MF_CLEN)
5598 flags |= HTX_SL_F_CLEN;
5599 if (h1m.body_len == 0)
5600 flags |= HTX_SL_F_BODYLESS;
5601 }
5602 sl->flags |= flags;
5603
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005604 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005605 * and the status code implies the presence of a message body, we must
5606 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005607 * for the keepalive compliance. If the applet announces a transfer-encoding
5608 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005609 */
5610 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005611 http_ctx->status >= 200 && http_ctx->status != 204 && http_ctx->status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005612 /* Add a new header */
5613 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
5614 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
5615 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005616 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005617 WILL_LJMP(lua_error(L));
5618 }
5619 }
5620
5621 /* Finalize headers. */
5622 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
5623 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005624 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005625 WILL_LJMP(lua_error(L));
5626 }
5627
5628 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
5629 b_reset(&res->buf);
5630 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
5631 WILL_LJMP(lua_error(L));
5632 }
5633
5634 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005635 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005636
5637 /* Headers sent, set the flag. */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02005638 http_ctx->flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005639 return 0;
5640
5641}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005642/* We will build the status line and the headers of the HTTP response.
5643 * We will try send at once if its not possible, we give back the hand
5644 * waiting for more room.
5645 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005646__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005647{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005648 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Willy Tarreauc12b3212022-05-27 11:08:15 +02005649 struct stconn *sc = appctx_sc(luactx->appctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02005650 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005651
5652 if (co_data(res)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02005653 sc_need_room(sc);
Christopher Fauleta2097962019-07-15 16:25:33 +02005654 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005655 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005656 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005657}
5658
5659
Christopher Fauleta2097962019-07-15 16:25:33 +02005660__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005661{
Christopher Fauleta2097962019-07-15 16:25:33 +02005662 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005663}
5664
Christopher Fauleta2097962019-07-15 16:25:33 +02005665/*
5666 *
5667 *
5668 * Class HTTP
5669 *
5670 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005671 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005672
5673/* Returns a struct hlua_txn if the stack entry "ud" is
5674 * a class stream, otherwise it throws an error.
5675 */
5676__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005677{
Christopher Fauleta2097962019-07-15 16:25:33 +02005678 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
5679}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005680
Christopher Fauleta2097962019-07-15 16:25:33 +02005681/* This function creates and push in the stack a HTTP object
5682 * according with a current TXN.
5683 */
5684static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
5685{
5686 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005687
Christopher Fauleta2097962019-07-15 16:25:33 +02005688 /* Check stack size. */
5689 if (!lua_checkstack(L, 3))
5690 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005691
Christopher Fauleta2097962019-07-15 16:25:33 +02005692 /* Create the object: obj[0] = userdata.
5693 * Note that the base of the Converters object is the
5694 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005695 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005696 lua_newtable(L);
5697 htxn = lua_newuserdata(L, sizeof(*htxn));
5698 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005699
5700 htxn->s = txn->s;
5701 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02005702 htxn->dir = txn->dir;
5703 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005704
5705 /* Pop a class stream metatable and affect it to the table. */
5706 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
5707 lua_setmetatable(L, -2);
5708
5709 return 1;
5710}
5711
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005712/* This function creates and returns an array containing the status-line
5713 * elements. This function does not fails.
5714 */
5715__LJMP static int hlua_http_get_stline(lua_State *L, struct htx_sl *sl)
5716{
5717 /* Create the table. */
5718 lua_newtable(L);
5719
5720 if (sl->flags & HTX_SL_F_IS_RESP) {
5721 lua_pushstring(L, "version");
5722 lua_pushlstring(L, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl));
5723 lua_settable(L, -3);
5724 lua_pushstring(L, "code");
5725 lua_pushlstring(L, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl));
5726 lua_settable(L, -3);
5727 lua_pushstring(L, "reason");
5728 lua_pushlstring(L, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl));
5729 lua_settable(L, -3);
5730 }
5731 else {
5732 lua_pushstring(L, "method");
5733 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
5734 lua_settable(L, -3);
5735 lua_pushstring(L, "uri");
5736 lua_pushlstring(L, HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl));
5737 lua_settable(L, -3);
5738 lua_pushstring(L, "version");
5739 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
5740 lua_settable(L, -3);
5741 }
5742 return 1;
5743}
5744
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005745/* This function creates ans returns an array of HTTP headers.
5746 * This function does not fails. It is used as wrapper with the
5747 * 2 following functions.
5748 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005749__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005750{
Christopher Fauleta2097962019-07-15 16:25:33 +02005751 struct htx *htx;
5752 int32_t pos;
5753
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005754 /* Create the table. */
5755 lua_newtable(L);
5756
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005757
Christopher Fauleta2097962019-07-15 16:25:33 +02005758 htx = htxbuf(&msg->chn->buf);
5759 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
5760 struct htx_blk *blk = htx_get_blk(htx, pos);
5761 enum htx_blk_type type = htx_get_blk_type(blk);
5762 struct ist n, v;
5763 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005764
Christopher Fauleta2097962019-07-15 16:25:33 +02005765 if (type == HTX_BLK_HDR) {
5766 n = htx_get_blk_name(htx,blk);
5767 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005768 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005769 else if (type == HTX_BLK_EOH)
5770 break;
5771 else
5772 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005773
Christopher Fauleta2097962019-07-15 16:25:33 +02005774 /* Check for existing entry:
5775 * assume that the table is on the top of the stack, and
5776 * push the key in the stack, the function lua_gettable()
5777 * perform the lookup.
5778 */
5779 lua_pushlstring(L, n.ptr, n.len);
5780 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005781
Christopher Fauleta2097962019-07-15 16:25:33 +02005782 switch (lua_type(L, -1)) {
5783 case LUA_TNIL:
5784 /* Table not found, create it. */
5785 lua_pop(L, 1); /* remove the nil value. */
5786 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
5787 lua_newtable(L); /* create and push empty table. */
5788 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5789 lua_rawseti(L, -2, 0); /* index header value (pop it). */
5790 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01005791 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005792
Christopher Fauleta2097962019-07-15 16:25:33 +02005793 case LUA_TTABLE:
5794 /* Entry found: push the value in the table. */
5795 len = lua_rawlen(L, -1);
5796 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5797 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
5798 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
5799 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005800
Christopher Fauleta2097962019-07-15 16:25:33 +02005801 default:
5802 /* Other cases are errors. */
5803 hlua_pusherror(L, "internal error during the parsing of headers.");
5804 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005805 }
5806 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005807 return 1;
5808}
5809
5810__LJMP static int hlua_http_req_get_headers(lua_State *L)
5811{
5812 struct hlua_txn *htxn;
5813
5814 MAY_LJMP(check_args(L, 1, "req_get_headers"));
5815 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5816
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005817 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005818 WILL_LJMP(lua_error(L));
5819
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005820 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005821}
5822
5823__LJMP static int hlua_http_res_get_headers(lua_State *L)
5824{
5825 struct hlua_txn *htxn;
5826
5827 MAY_LJMP(check_args(L, 1, "res_get_headers"));
5828 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5829
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005830 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005831 WILL_LJMP(lua_error(L));
5832
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005833 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005834}
5835
5836/* This function replace full header, or just a value in
5837 * the request or in the response. It is a wrapper fir the
5838 * 4 following functions.
5839 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005840__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005841{
5842 size_t name_len;
5843 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5844 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
5845 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02005846 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02005847 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005848
Dragan Dosen26743032019-04-30 15:54:36 +02005849 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005850 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
5851
Christopher Fauleta2097962019-07-15 16:25:33 +02005852 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005853 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02005854 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005855 return 0;
5856}
5857
5858__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
5859{
5860 struct hlua_txn *htxn;
5861
5862 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5863 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5864
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005865 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005866 WILL_LJMP(lua_error(L));
5867
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005868 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005869}
5870
5871__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
5872{
5873 struct hlua_txn *htxn;
5874
5875 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
5876 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5877
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005878 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005879 WILL_LJMP(lua_error(L));
5880
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005881 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005882}
5883
5884__LJMP static int hlua_http_req_rep_val(lua_State *L)
5885{
5886 struct hlua_txn *htxn;
5887
5888 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5889 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5890
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005891 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005892 WILL_LJMP(lua_error(L));
5893
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005894 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005895}
5896
5897__LJMP static int hlua_http_res_rep_val(lua_State *L)
5898{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005899 struct hlua_txn *htxn;
5900
5901 MAY_LJMP(check_args(L, 4, "res_rep_val"));
5902 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5903
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005904 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005905 WILL_LJMP(lua_error(L));
5906
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005907 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005908}
5909
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005910/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005911 * It is a wrapper for the 2 following functions.
5912 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005913__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005914{
5915 size_t len;
5916 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005917 struct htx *htx = htxbuf(&msg->chn->buf);
5918 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005919
Christopher Fauleta2097962019-07-15 16:25:33 +02005920 ctx.blk = NULL;
5921 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5922 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005923 return 0;
5924}
5925
5926__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5927{
5928 struct hlua_txn *htxn;
5929
5930 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5931 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5932
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005933 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005934 WILL_LJMP(lua_error(L));
5935
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005936 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005937}
5938
5939__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5940{
5941 struct hlua_txn *htxn;
5942
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005943 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005944 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5945
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005946 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005947 WILL_LJMP(lua_error(L));
5948
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005949 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005950}
5951
5952/* This function adds an header. It is a wrapper used by
5953 * the 2 following functions.
5954 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005955__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005956{
5957 size_t name_len;
5958 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5959 size_t value_len;
5960 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005961 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005962
Christopher Fauleta2097962019-07-15 16:25:33 +02005963 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5964 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005965 return 0;
5966}
5967
Christopher Fauletdf97ac42020-02-26 16:57:19 +01005968__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5969{
5970 struct hlua_txn *htxn;
5971
5972 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5973 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5974
5975 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
5976 WILL_LJMP(lua_error(L));
5977
5978 return hlua_http_add_hdr(L, &htxn->s->txn->req);
5979}
5980
5981__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5982{
5983 struct hlua_txn *htxn;
5984
5985 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5986 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5987
5988 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
5989 WILL_LJMP(lua_error(L));
5990
5991 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
5992}
5993
5994static int hlua_http_req_set_hdr(lua_State *L)
5995{
5996 struct hlua_txn *htxn;
5997
5998 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5999 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6000
6001 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6002 WILL_LJMP(lua_error(L));
6003
6004 hlua_http_del_hdr(L, &htxn->s->txn->req);
6005 return hlua_http_add_hdr(L, &htxn->s->txn->req);
6006}
6007
6008static int hlua_http_res_set_hdr(lua_State *L)
6009{
6010 struct hlua_txn *htxn;
6011
6012 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
6013 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6014
6015 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6016 WILL_LJMP(lua_error(L));
6017
6018 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
6019 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
6020}
6021
6022/* This function set the method. */
6023static int hlua_http_req_set_meth(lua_State *L)
6024{
6025 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6026 size_t name_len;
6027 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6028
6029 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6030 WILL_LJMP(lua_error(L));
6031
6032 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
6033 return 1;
6034}
6035
6036/* This function set the method. */
6037static int hlua_http_req_set_path(lua_State *L)
6038{
6039 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6040 size_t name_len;
6041 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6042
6043 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6044 WILL_LJMP(lua_error(L));
6045
6046 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
6047 return 1;
6048}
6049
6050/* This function set the query-string. */
6051static int hlua_http_req_set_query(lua_State *L)
6052{
6053 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6054 size_t name_len;
6055 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6056
6057 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6058 WILL_LJMP(lua_error(L));
6059
6060 /* Check length. */
6061 if (name_len > trash.size - 1) {
6062 lua_pushboolean(L, 0);
6063 return 1;
6064 }
6065
6066 /* Add the mark question as prefix. */
6067 chunk_reset(&trash);
6068 trash.area[trash.data++] = '?';
6069 memcpy(trash.area + trash.data, name, name_len);
6070 trash.data += name_len;
6071
6072 lua_pushboolean(L,
6073 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
6074 return 1;
6075}
6076
6077/* This function set the uri. */
6078static int hlua_http_req_set_uri(lua_State *L)
6079{
6080 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6081 size_t name_len;
6082 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6083
6084 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
6085 WILL_LJMP(lua_error(L));
6086
6087 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
6088 return 1;
6089}
6090
6091/* This function set the response code & optionally reason. */
6092static int hlua_http_res_set_status(lua_State *L)
6093{
6094 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
6095 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
6096 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6097 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
6098
6099 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
6100 WILL_LJMP(lua_error(L));
6101
6102 http_res_set_status(code, reason, htxn->s);
6103 return 0;
6104}
6105
6106/*
6107 *
6108 *
6109 * Class HTTPMessage
6110 *
6111 *
6112 */
6113
6114/* Returns a struct http_msg if the stack entry "ud" is a class HTTPMessage,
6115 * otherwise it throws an error.
6116 */
6117__LJMP static struct http_msg *hlua_checkhttpmsg(lua_State *L, int ud)
6118{
6119 return MAY_LJMP(hlua_checkudata(L, ud, class_http_msg_ref));
6120}
6121
6122/* Creates and pushes on the stack a HTTP object according with a current TXN.
6123 */
Christopher Faulet78c35472020-02-26 17:14:08 +01006124static int hlua_http_msg_new(lua_State *L, struct http_msg *msg)
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006125{
6126 /* Check stack size. */
6127 if (!lua_checkstack(L, 3))
6128 return 0;
6129
6130 lua_newtable(L);
6131 lua_pushlightuserdata(L, msg);
6132 lua_rawseti(L, -2, 0);
6133
6134 /* Create the "channel" field that contains the request channel object. */
6135 lua_pushstring(L, "channel");
6136 if (!hlua_channel_new(L, msg->chn))
6137 return 0;
6138 lua_rawset(L, -3);
6139
6140 /* Pop a class stream metatable and affect it to the table. */
6141 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_msg_ref);
6142 lua_setmetatable(L, -2);
6143
6144 return 1;
6145}
6146
6147/* Helper function returning a filter attached to the HTTP message at the
6148 * position <ud> in the stack, filling the current offset and length of the
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006149 * filter. If no filter is attached, NULL is returned and <offset> and <len> are
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006150 * filled with output and input length respectively.
6151 */
6152static struct filter *hlua_http_msg_filter(lua_State *L, int ud, struct http_msg *msg, size_t *offset, size_t *len)
6153{
6154 struct channel *chn = msg->chn;
6155 struct htx *htx = htxbuf(&chn->buf);
6156 struct filter *filter = NULL;
6157
6158 *offset = co_data(msg->chn);
6159 *len = htx->data - co_data(msg->chn);
6160
6161 if (lua_getfield(L, ud, "__filter") == LUA_TLIGHTUSERDATA) {
6162 filter = lua_touserdata (L, -1);
6163 if (msg->msg_state >= HTTP_MSG_DATA) {
6164 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6165
6166 *offset = flt_ctx->cur_off[CHN_IDX(chn)];
6167 *len = flt_ctx->cur_len[CHN_IDX(chn)];
6168 }
6169 }
6170
6171 lua_pop(L, 1);
6172 return filter;
6173}
6174
6175/* Returns true if the channel attached to the HTTP message is the response
6176 * channel.
6177 */
6178__LJMP static int hlua_http_msg_is_resp(lua_State *L)
6179{
6180 struct http_msg *msg;
6181
6182 MAY_LJMP(check_args(L, 1, "is_resp"));
6183 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6184
6185 lua_pushboolean(L, !!(msg->chn->flags & CF_ISRESP));
6186 return 1;
6187}
6188
6189/* Returns an array containing the elements status-line of the HTTP message. It relies
6190 * on hlua_http_get_stline().
6191 */
6192__LJMP static int hlua_http_msg_get_stline(lua_State *L)
6193{
6194 struct http_msg *msg;
6195 struct htx *htx;
6196 struct htx_sl *sl;
6197
6198 MAY_LJMP(check_args(L, 1, "get_stline"));
6199 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6200
6201 if (msg->msg_state > HTTP_MSG_BODY)
6202 WILL_LJMP(lua_error(L));
6203
6204 htx = htxbuf(&msg->chn->buf);
6205 sl = http_get_stline(htx);
6206 if (!sl)
6207 return 0;
6208 return hlua_http_get_stline(L, sl);
6209}
6210
6211/* Returns an array containing all headers of the HTTP message. it relies on
6212 * hlua_http_get_headers().
6213 */
6214__LJMP static int hlua_http_msg_get_headers(lua_State *L)
6215{
6216 struct http_msg *msg;
6217
6218 MAY_LJMP(check_args(L, 1, "get_headers"));
6219 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6220
6221 if (msg->msg_state > HTTP_MSG_BODY)
6222 WILL_LJMP(lua_error(L));
6223
6224 return hlua_http_get_headers(L, msg);
6225}
6226
6227/* Deletes all occurrences of an header in the HTTP message matching on its
6228 * name. It relies on hlua_http_del_hdr().
6229 */
6230__LJMP static int hlua_http_msg_del_hdr(lua_State *L)
6231{
6232 struct http_msg *msg;
6233
6234 MAY_LJMP(check_args(L, 2, "del_header"));
6235 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6236
6237 if (msg->msg_state > HTTP_MSG_BODY)
6238 WILL_LJMP(lua_error(L));
6239
6240 return hlua_http_del_hdr(L, msg);
6241}
6242
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006243/* Matches the full value line of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006244 * message given its name against a regex and replaces it if it matches. It
6245 * relies on hlua_http_rep_hdr().
6246 */
6247__LJMP static int hlua_http_msg_rep_hdr(lua_State *L)
6248{
6249 struct http_msg *msg;
6250
6251 MAY_LJMP(check_args(L, 4, "rep_header"));
6252 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6253
6254 if (msg->msg_state > HTTP_MSG_BODY)
6255 WILL_LJMP(lua_error(L));
6256
6257 return hlua_http_rep_hdr(L, msg, 1);
6258}
6259
Ilya Shipitsinbd6b4be2021-10-15 16:18:21 +05006260/* Matches all comma-separated values of all occurrences of an header in the HTTP
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006261 * message given its name against a regex and replaces it if it matches. It
6262 * relies on hlua_http_rep_hdr().
6263 */
6264__LJMP static int hlua_http_msg_rep_val(lua_State *L)
6265{
6266 struct http_msg *msg;
6267
6268 MAY_LJMP(check_args(L, 4, "rep_value"));
6269 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6270
6271 if (msg->msg_state > HTTP_MSG_BODY)
6272 WILL_LJMP(lua_error(L));
6273
6274 return hlua_http_rep_hdr(L, msg, 0);
6275}
6276
6277/* Add an header in the HTTP message. It relies on hlua_http_add_hdr() */
6278__LJMP static int hlua_http_msg_add_hdr(lua_State *L)
6279{
6280 struct http_msg *msg;
6281
6282 MAY_LJMP(check_args(L, 3, "add_header"));
6283 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6284
6285 if (msg->msg_state > HTTP_MSG_BODY)
6286 WILL_LJMP(lua_error(L));
6287
6288 return hlua_http_add_hdr(L, msg);
6289}
6290
6291/* Add an header in the HTTP message removing existing headers with the same
6292 * name. It relies on hlua_http_del_hdr() and hlua_http_add_hdr().
6293 */
6294__LJMP static int hlua_http_msg_set_hdr(lua_State *L)
6295{
6296 struct http_msg *msg;
6297
6298 MAY_LJMP(check_args(L, 3, "set_header"));
6299 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6300
6301 if (msg->msg_state > HTTP_MSG_BODY)
6302 WILL_LJMP(lua_error(L));
6303
6304 hlua_http_del_hdr(L, msg);
6305 return hlua_http_add_hdr(L, msg);
6306}
6307
6308/* Rewrites the request method. It relies on http_req_replace_stline(). */
6309__LJMP static int hlua_http_msg_set_meth(lua_State *L)
6310{
6311 struct stream *s;
6312 struct http_msg *msg;
6313 const char *name;
6314 size_t name_len;
6315
6316 MAY_LJMP(check_args(L, 2, "set_method"));
6317 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6318 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6319
6320 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6321 WILL_LJMP(lua_error(L));
6322
6323 s = chn_strm(msg->chn);
6324 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, s->be, s) != -1);
6325 return 1;
6326}
6327
6328/* Rewrites the request path. It relies on http_req_replace_stline(). */
6329__LJMP static int hlua_http_msg_set_path(lua_State *L)
6330{
6331 struct stream *s;
6332 struct http_msg *msg;
6333 const char *name;
6334 size_t name_len;
6335
6336 MAY_LJMP(check_args(L, 2, "set_path"));
6337 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6338 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6339
6340 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6341 WILL_LJMP(lua_error(L));
6342
6343 s = chn_strm(msg->chn);
6344 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, s->be, s) != -1);
6345 return 1;
6346}
6347
6348/* Rewrites the request query-string. It relies on http_req_replace_stline(). */
6349__LJMP static int hlua_http_msg_set_query(lua_State *L)
6350{
6351 struct stream *s;
6352 struct http_msg *msg;
6353 const char *name;
6354 size_t name_len;
6355
6356 MAY_LJMP(check_args(L, 2, "set_query"));
6357 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6358 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6359
6360 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6361 WILL_LJMP(lua_error(L));
6362
6363 /* Check length. */
6364 if (name_len > trash.size - 1) {
6365 lua_pushboolean(L, 0);
6366 return 1;
6367 }
6368
6369 /* Add the mark question as prefix. */
6370 chunk_reset(&trash);
6371 trash.area[trash.data++] = '?';
6372 memcpy(trash.area + trash.data, name, name_len);
6373 trash.data += name_len;
6374
6375 s = chn_strm(msg->chn);
6376 lua_pushboolean(L, http_req_replace_stline(2, trash.area, trash.data, s->be, s) != -1);
6377 return 1;
6378}
6379
6380/* Rewrites the request URI. It relies on http_req_replace_stline(). */
6381__LJMP static int hlua_http_msg_set_uri(lua_State *L)
6382{
6383 struct stream *s;
6384 struct http_msg *msg;
6385 const char *name;
6386 size_t name_len;
6387
6388 MAY_LJMP(check_args(L, 2, "set_uri"));
6389 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6390 name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
6391
6392 if ((msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6393 WILL_LJMP(lua_error(L));
6394
6395 s = chn_strm(msg->chn);
6396 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, s->be, s) != -1);
6397 return 1;
6398}
6399
6400/* Rewrites the response status code. It relies on http_res_set_status(). */
6401__LJMP static int hlua_http_msg_set_status(lua_State *L)
6402{
6403 struct http_msg *msg;
6404 unsigned int code;
6405 const char *reason;
6406 size_t reason_len;
6407
6408 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6409 code = MAY_LJMP(luaL_checkinteger(L, 2));
6410 reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, &reason_len));
6411
6412 if (!(msg->chn->flags & CF_ISRESP) || msg->msg_state > HTTP_MSG_BODY)
6413 WILL_LJMP(lua_error(L));
6414
6415 lua_pushboolean(L, http_res_set_status(code, ist2(reason, reason_len), chn_strm(msg->chn)) != -1);
6416 return 1;
6417}
6418
6419/* Returns true if the HTTP message is full. */
6420__LJMP static int hlua_http_msg_is_full(lua_State *L)
6421{
6422 struct http_msg *msg;
6423
6424 MAY_LJMP(check_args(L, 1, "is_full"));
6425 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6426 lua_pushboolean(L, channel_full(msg->chn, 0));
6427 return 1;
6428}
6429
6430/* Returns true if the HTTP message may still receive data. */
6431__LJMP static int hlua_http_msg_may_recv(lua_State *L)
6432{
6433 struct http_msg *msg;
6434 struct htx *htx;
6435
6436 MAY_LJMP(check_args(L, 1, "may_recv"));
6437 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6438 htx = htxbuf(&msg->chn->buf);
6439 lua_pushboolean(L, (htx_expect_more(htx) && !channel_input_closed(msg->chn) && channel_may_recv(msg->chn)));
6440 return 1;
6441}
6442
6443/* Returns true if the HTTP message EOM was received */
6444__LJMP static int hlua_http_msg_is_eom(lua_State *L)
6445{
6446 struct http_msg *msg;
6447 struct htx *htx;
6448
6449 MAY_LJMP(check_args(L, 1, "may_recv"));
6450 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6451 htx = htxbuf(&msg->chn->buf);
6452 lua_pushboolean(L, !htx_expect_more(htx));
6453 return 1;
6454}
6455
6456/* Returns the number of bytes available in the input side of the HTTP
6457 * message. This function never fails.
6458 */
6459__LJMP static int hlua_http_msg_get_in_len(lua_State *L)
6460{
6461 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006462 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006463
6464 MAY_LJMP(check_args(L, 1, "input"));
6465 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006466 hlua_http_msg_filter(L, 1, msg, &output, &input);
6467 lua_pushinteger(L, input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006468 return 1;
6469}
6470
6471/* Returns the number of bytes available in the output side of the HTTP
6472 * message. This function never fails.
6473 */
6474__LJMP static int hlua_http_msg_get_out_len(lua_State *L)
6475{
6476 struct http_msg *msg;
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006477 size_t output, input;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006478
6479 MAY_LJMP(check_args(L, 1, "output"));
6480 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Christopher Fauleteae8afa2020-02-26 17:15:48 +01006481 hlua_http_msg_filter(L, 1, msg, &output, &input);
6482 lua_pushinteger(L, output);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006483 return 1;
6484}
6485
6486/* Copies at most <len> bytes of DATA blocks from the HTTP message <msg>
6487 * starting at the offset <offset> and put it in a string LUA variables. It
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006488 * returns the built string length. It stops on the first non-DATA HTX
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006489 * block. This function is called during the payload filtering, so the headers
6490 * are already scheduled for output (from the filter point of view).
6491 */
6492static int _hlua_http_msg_dup(struct http_msg *msg, lua_State *L, size_t offset, size_t len)
6493{
6494 struct htx *htx = htxbuf(&msg->chn->buf);
6495 struct htx_blk *blk;
6496 struct htx_ret htxret;
6497 luaL_Buffer b;
6498 int ret = 0;
6499
6500 luaL_buffinit(L, &b);
6501 htxret = htx_find_offset(htx, offset);
6502 for (blk = htxret.blk, offset = htxret.ret; blk && len; blk = htx_get_next_blk(htx, blk)) {
6503 enum htx_blk_type type = htx_get_blk_type(blk);
6504 struct ist v;
6505
6506 switch (type) {
6507 case HTX_BLK_UNUSED:
6508 break;
6509
6510 case HTX_BLK_DATA:
6511 v = htx_get_blk_value(htx, blk);
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006512 v = istadv(v, offset);
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006513 v = isttrim(v, len);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006514
6515 luaL_addlstring(&b, v.ptr, v.len);
6516 ret += v.len;
6517 break;
6518
6519 default:
vishnu0af4bd72021-10-24 06:46:24 +05306520 if (!ret)
6521 goto no_data;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006522 goto end;
6523 }
6524 offset = 0;
6525 }
6526
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006527end:
vishnu0af4bd72021-10-24 06:46:24 +05306528 if (!ret && (htx->flags & HTX_FL_EOM))
6529 goto no_data;
6530 luaL_pushresult(&b);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006531 return ret;
vishnu0af4bd72021-10-24 06:46:24 +05306532
6533 no_data:
6534 /* Remove the empty string and push nil on the stack */
6535 lua_pop(L, 1);
6536 lua_pushnil(L);
6537 return 0;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006538}
6539
6540/* Copies the string <str> to the HTTP message <msg> at the offset
6541 * <offset>. This function returns -1 if data cannot be copied. Otherwise, it
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006542 * returns the amount of data written. This function is responsible to update
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006543 * the filter context.
6544 */
6545static int _hlua_http_msg_insert(struct http_msg *msg, struct filter *filter, struct ist str, size_t offset)
6546{
6547 struct htx *htx = htx_from_buf(&msg->chn->buf);
6548 struct htx_ret htxret;
6549 int /*max, */ret = 0;
6550
6551 /* Nothing to do, just return */
6552 if (unlikely(istlen(str) == 0))
6553 goto end;
6554
6555 if (istlen(str) > htx_free_data_space(htx)) {
6556 ret = -1;
6557 goto end;
6558 }
6559
6560 htxret = htx_find_offset(htx, offset);
6561 if (!htxret.blk || htx_get_blk_type(htxret.blk) != HTX_BLK_DATA) {
6562 if (!htx_add_last_data(htx, str))
6563 goto end;
6564 }
6565 else {
6566 struct ist v = htx_get_blk_value(htx, htxret.blk);
6567 v.ptr += htxret.ret;
6568 v.len = 0;
6569 if (!htx_replace_blk_value(htx, htxret.blk, v, str))
6570 goto end;
6571 }
6572 ret = str.len;
6573 if (ret) {
6574 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6575 flt_update_offsets(filter, msg->chn, ret);
6576 flt_ctx->cur_len[CHN_IDX(msg->chn)] += ret;
6577 }
6578
6579 end:
6580 htx_to_buf(htx, &msg->chn->buf);
6581 return ret;
6582}
6583
6584/* Helper function removing at most <len> bytes of DATA blocks at the absolute
6585 * position <offset>. It stops on the first non-DATA HTX block. This function is
6586 * called during the payload filtering, so the headers are already scheduled for
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006587 * output (from the filter point of view). This function is responsible to
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006588 * update the filter context.
6589 */
6590static void _hlua_http_msg_delete(struct http_msg *msg, struct filter *filter, size_t offset, size_t len)
6591{
6592 struct hlua_flt_ctx *flt_ctx = filter->ctx;
6593 struct htx *htx = htx_from_buf(&msg->chn->buf);
6594 struct htx_blk *blk;
6595 struct htx_ret htxret;
6596 size_t ret = 0;
6597
6598 /* Be sure <len> is always the amount of DATA to remove */
6599 if (htx->data == offset+len && htx_get_tail_type(htx) == HTX_BLK_DATA) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006600 /* When htx tail type == HTX_BLK_DATA, no need to take care
6601 * of special blocks like HTX_BLK_EOT.
6602 * We simply truncate after offset
6603 * (truncate targeted blk and discard the following ones)
6604 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006605 htx_truncate(htx, offset);
6606 ret = len;
6607 goto end;
6608 }
6609
6610 htxret = htx_find_offset(htx, offset);
6611 blk = htxret.blk;
6612 if (htxret.ret) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006613 /* dealing with offset: we need to trim targeted blk */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006614 struct ist v;
6615
6616 if (htx_get_blk_type(blk) != HTX_BLK_DATA)
6617 goto end;
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006618
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006619 v = htx_get_blk_value(htx, blk);
Tim Duesterhusa029d782022-10-08 12:33:18 +02006620 v = istadv(v, htxret.ret);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006621
Tim Duesterhus2471f5c2021-11-08 09:05:01 +01006622 v = isttrim(v, len);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006623 /* trimming data in blk: discard everything after the offset
6624 * (replace 'v' with 'IST_NULL')
6625 */
Tim Duesterhusb113b5c2021-09-15 13:58:44 +02006626 blk = htx_replace_blk_value(htx, blk, v, IST_NULL);
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006627 if (blk && v.len < len) {
6628 /* In this case, caller wants to keep removing data,
6629 * but we need to spare current blk
6630 * because it was already trimmed
6631 */
6632 blk = htx_get_next_blk(htx, blk);
6633 }
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006634 len -= v.len;
6635 ret += v.len;
6636 }
6637
6638
6639 while (blk && len) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006640 /* there is more data that needs to be discarded */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006641 enum htx_blk_type type = htx_get_blk_type(blk);
6642 uint32_t sz = htx_get_blksz(blk);
6643
6644 switch (type) {
6645 case HTX_BLK_UNUSED:
6646 break;
6647
6648 case HTX_BLK_DATA:
6649 if (len < sz) {
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006650 /* don't discard whole blk, only part of it
6651 * (from the beginning)
6652 */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006653 htx_cut_data_blk(htx, blk, len);
6654 ret += len;
6655 goto end;
6656 }
6657 break;
6658
6659 default:
Aurelien DARRAGONbcbcf982022-09-28 19:08:15 +02006660 /* HTX_BLK_EOT blk won't be removed */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006661 goto end;
6662 }
6663
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006664 /* Remove all the data block */
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006665 len -= sz;
6666 ret += sz;
6667 blk = htx_remove_blk(htx, blk);
6668 }
6669
6670end:
6671 flt_update_offsets(filter, msg->chn, -ret);
6672 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
6673 /* WARNING: we don't call htx_to_buf() on purpose, because we don't want
6674 * to loose the EOM flag if the message is empty.
6675 */
6676}
6677
6678/* Copies input data found in an HTTP message. Unlike the channel function used
6679 * to duplicate raw data, this one can only be called inside a filter, from
6680 * http_payload callback. So it cannot yield. An exception is returned if it is
6681 * called from another callback. If nothing was copied, a nil value is pushed on
6682 * the stack.
6683 */
6684__LJMP static int hlua_http_msg_get_body(lua_State *L)
6685{
6686 struct http_msg *msg;
6687 struct filter *filter;
6688 size_t output, input;
6689 int offset, len;
6690
6691 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
6692 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
6693 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6694
6695 if (msg->msg_state < HTTP_MSG_DATA)
6696 WILL_LJMP(lua_error(L));
6697
6698 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6699 if (!filter || !hlua_filter_from_payload(filter))
6700 WILL_LJMP(lua_error(L));
6701
6702 if (!ci_data(msg->chn) && channel_input_closed(msg->chn)) {
6703 lua_pushnil(L);
6704 return 1;
6705 }
6706
6707 offset = output;
6708 if (lua_gettop(L) > 1) {
6709 offset = MAY_LJMP(luaL_checkinteger(L, 2));
6710 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006711 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006712 offset += output;
6713 if (offset < output || offset > input + output) {
6714 lua_pushfstring(L, "offset out of range.");
6715 WILL_LJMP(lua_error(L));
6716 }
6717 }
6718 len = output + input - offset;
6719 if (lua_gettop(L) == 3) {
6720 len = MAY_LJMP(luaL_checkinteger(L, 3));
6721 if (!len)
6722 goto dup;
6723 if (len == -1)
6724 len = global.tune.bufsize;
6725 if (len < 0) {
6726 lua_pushfstring(L, "length out of range.");
6727 WILL_LJMP(lua_error(L));
6728 }
6729 }
6730
6731 dup:
6732 _hlua_http_msg_dup(msg, L, offset, len);
6733 return 1;
6734}
6735
6736/* Appends a string to the HTTP message, after all existing DATA blocks but
6737 * before the trailers, if any. It returns the amount of data written or -1 if
6738 * nothing was copied. Unlike the channel function used to append data, this one
6739 * can only be called inside a filter, from http_payload callback. So it cannot
6740 * yield. An exception is returned if it is called from another callback.
6741 */
6742__LJMP static int hlua_http_msg_append(lua_State *L)
6743{
6744 struct http_msg *msg;
6745 struct filter *filter;
6746 const char *str;
6747 size_t offset, len, sz;
6748 int ret;
6749
6750 MAY_LJMP(check_args(L, 2, "append"));
6751 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6752
6753 if (msg->msg_state < HTTP_MSG_DATA)
6754 WILL_LJMP(lua_error(L));
6755
6756 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6757 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6758 if (!filter || !hlua_filter_from_payload(filter))
6759 WILL_LJMP(lua_error(L));
6760
6761 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset+len);
6762 lua_pushinteger(L, ret);
6763 return 1;
6764}
6765
6766/* Prepends a string to the HTTP message, before all existing DATA blocks. It
6767 * returns the amount of data written or -1 if nothing was copied. Unlike the
6768 * channel function used to prepend data, this one can only be called inside a
6769 * filter, from http_payload callback. So it cannot yield. An exception is
6770 * returned if it is called from another callback.
6771 */
6772__LJMP static int hlua_http_msg_prepend(lua_State *L)
6773{
6774 struct http_msg *msg;
6775 struct filter *filter;
6776 const char *str;
6777 size_t offset, len, sz;
6778 int ret;
6779
6780 MAY_LJMP(check_args(L, 2, "prepend"));
6781 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006782
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006783 if (msg->msg_state < HTTP_MSG_DATA)
6784 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006785
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006786 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6787 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6788 if (!filter || !hlua_filter_from_payload(filter))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006789 WILL_LJMP(lua_error(L));
6790
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006791 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6792 lua_pushinteger(L, ret);
6793 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006794}
6795
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006796/* Inserts a string to the HTTP message at a given offset. By default the string
6797 * is appended at the end of DATA blocks. It returns the amount of data written
6798 * or -1 if nothing was copied. Unlike the channel function used to insert data,
6799 * this one can only be called inside a filter, from http_payload callback. So
6800 * it cannot yield. An exception is returned if it is called from another
6801 * callback.
6802 */
6803__LJMP static int hlua_http_msg_insert_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006804{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006805 struct http_msg *msg;
6806 struct filter *filter;
6807 const char *str;
6808 size_t input, output, sz;
6809 int offset;
6810 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006811
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006812 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
6813 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006814 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006815
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006816 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006817 WILL_LJMP(lua_error(L));
6818
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006819 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006820 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006821 if (!filter || !hlua_filter_from_payload(filter))
6822 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006823
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006824 offset = output;
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006825 if (lua_gettop(L) > 2) {
6826 offset = MAY_LJMP(luaL_checkinteger(L, 3));
6827 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006828 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006829 offset += output;
Aurelien DARRAGON7fdba0a2022-09-28 16:03:45 +02006830 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006831 lua_pushfstring(L, "offset out of range.");
6832 WILL_LJMP(lua_error(L));
6833 }
6834 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006835
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006836 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6837 lua_pushinteger(L, ret);
6838 return 1;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006839}
6840
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006841/* Removes a given amount of data from the HTTP message at a given offset. By
6842 * default all DATA blocks are removed. It returns the amount of data
6843 * removed. Unlike the channel function used to remove data, this one can only
6844 * be called inside a filter, from http_payload callback. So it cannot yield. An
6845 * exception is returned if it is called from another callback.
6846 */
6847__LJMP static int hlua_http_msg_del_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006848{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006849 struct http_msg *msg;
6850 struct filter *filter;
6851 size_t input, output;
6852 int offset, len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006853
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006854 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
Boyang Lie0c54352022-05-10 17:47:23 +00006855 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006856 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006857
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006858 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006859 WILL_LJMP(lua_error(L));
6860
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006861 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006862 if (!filter || !hlua_filter_from_payload(filter))
6863 WILL_LJMP(lua_error(L));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006864
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006865 offset = output;
Boyang Lie0c54352022-05-10 17:47:23 +00006866 if (lua_gettop(L) > 1) {
6867 offset = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006868 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006869 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006870 offset += output;
Aurelien DARRAGONd7c71b02022-09-28 15:52:18 +02006871 if (offset > output + input) {
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006872 lua_pushfstring(L, "offset out of range.");
6873 WILL_LJMP(lua_error(L));
6874 }
6875 }
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006876
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006877 len = output + input - offset;
Boyang Lie0c54352022-05-10 17:47:23 +00006878 if (lua_gettop(L) == 3) {
6879 len = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006880 if (!len)
6881 goto end;
6882 if (len == -1)
6883 len = output + input - offset;
6884 if (len < 0 || offset + len > output + input) {
6885 lua_pushfstring(L, "length out of range.");
6886 WILL_LJMP(lua_error(L));
6887 }
6888 }
6889
6890 _hlua_http_msg_delete(msg, filter, offset, len);
6891
6892 end:
6893 lua_pushinteger(L, len);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006894 return 1;
6895}
6896
Ilya Shipitsinff0f2782021-08-22 22:18:07 +05006897/* Replaces a given amount of data at the given offset by a string. By default,
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006898 * all remaining data are removed, accordingly to the filter context. It returns
6899 * the amount of data written or -1 if nothing was copied. Unlike the channel
6900 * function used to replace data, this one can only be called inside a filter,
6901 * from http_payload callback. So it cannot yield. An exception is returned if
6902 * it is called from another callback.
6903 */
6904__LJMP static int hlua_http_msg_set_data(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006905{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006906 struct http_msg *msg;
6907 struct filter *filter;
6908 struct htx *htx;
6909 const char *str;
6910 size_t input, output, sz;
6911 int offset, len;
6912 int ret;
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02006913
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006914 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
6915 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
6916 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6917
6918 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006919 WILL_LJMP(lua_error(L));
6920
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006921 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6922 filter = hlua_http_msg_filter(L, 1, msg, &output, &input);
6923 if (!filter || !hlua_filter_from_payload(filter))
6924 WILL_LJMP(lua_error(L));
6925
6926 offset = output;
6927 if (lua_gettop(L) > 2) {
6928 offset = MAY_LJMP(luaL_checkinteger(L, 3));
6929 if (offset < 0)
Christopher Faulet70c43452021-08-13 08:11:00 +02006930 offset = MAX(0, (int)input + offset);
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006931 offset += output;
6932 if (offset < output || offset > input + output) {
6933 lua_pushfstring(L, "offset out of range.");
6934 WILL_LJMP(lua_error(L));
6935 }
6936 }
6937
6938 len = output + input - offset;
6939 if (lua_gettop(L) == 4) {
6940 len = MAY_LJMP(luaL_checkinteger(L, 4));
6941 if (!len)
6942 goto set;
6943 if (len == -1)
6944 len = output + input - offset;
6945 if (len < 0 || offset + len > output + input) {
6946 lua_pushfstring(L, "length out of range.");
6947 WILL_LJMP(lua_error(L));
6948 }
6949 }
6950
6951 set:
6952 /* Be sure we can copied the string once input data will be removed. */
6953 htx = htx_from_buf(&msg->chn->buf);
6954 if (sz > htx_free_data_space(htx) + len)
6955 lua_pushinteger(L, -1);
6956 else {
6957 _hlua_http_msg_delete(msg, filter, offset, len);
6958 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
6959 lua_pushinteger(L, ret);
6960 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006961 return 1;
6962}
6963
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006964/* Prepends data into an HTTP message and forward it, from the filter point of
6965 * view. It returns the amount of data written or -1 if nothing was sent. Unlike
6966 * the channel function used to send data, this one can only be called inside a
6967 * filter, from http_payload callback. So it cannot yield. An exception is
6968 * returned if it is called from another callback.
6969 */
6970__LJMP static int hlua_http_msg_send(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006971{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006972 struct http_msg *msg;
6973 struct filter *filter;
6974 struct htx *htx;
6975 const char *str;
6976 size_t offset, len, sz;
6977 int ret;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006978
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006979 MAY_LJMP(check_args(L, 2, "send"));
6980 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
6981
6982 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02006983 WILL_LJMP(lua_error(L));
6984
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006985 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
6986 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
6987 if (!filter || !hlua_filter_from_payload(filter))
6988 WILL_LJMP(lua_error(L));
6989
6990 /* Return an error if the channel's output is closed */
6991 if (unlikely(channel_output_closed(msg->chn))) {
6992 lua_pushinteger(L, -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01006993 return 1;
6994 }
6995
Christopher Fauletdf97ac42020-02-26 16:57:19 +01006996 htx = htx_from_buf(&msg->chn->buf);
6997 if (sz > htx_free_data_space(htx)) {
6998 lua_pushinteger(L, -1);
6999 return 1;
7000 }
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007001
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007002 ret = _hlua_http_msg_insert(msg, filter, ist2(str, sz), offset);
7003 if (ret > 0) {
7004 struct hlua_flt_ctx *flt_ctx = filter->ctx;
7005
7006 FLT_OFF(filter, msg->chn) += ret;
7007 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
7008 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
7009 }
7010
7011 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007012 return 1;
7013}
7014
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007015/* Forwards a given amount of bytes. It return -1 if the channel's output is
7016 * closed. Otherwise, it returns the number of bytes forwarded. Unlike the
7017 * channel function used to forward data, this one can only be called inside a
7018 * filter, from http_payload callback. So it cannot yield. An exception is
7019 * returned if it is called from another callback. All other functions deal with
7020 * DATA block, this one not.
7021*/
7022__LJMP static int hlua_http_msg_forward(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007023{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007024 struct http_msg *msg;
7025 struct filter *filter;
7026 size_t offset, len;
7027 int fwd, ret = 0;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007028
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007029 MAY_LJMP(check_args(L, 2, "forward"));
7030 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7031
7032 if (msg->msg_state < HTTP_MSG_DATA)
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007033 WILL_LJMP(lua_error(L));
7034
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007035 fwd = MAY_LJMP(luaL_checkinteger(L, 2));
7036 filter = hlua_http_msg_filter(L, 1, msg, &offset, &len);
7037 if (!filter || !hlua_filter_from_payload(filter))
7038 WILL_LJMP(lua_error(L));
7039
7040 /* Nothing to do, just return */
7041 if (!fwd)
7042 goto end;
7043
7044 /* Return an error if the channel's output is closed */
7045 if (unlikely(channel_output_closed(msg->chn))) {
7046 ret = -1;
7047 goto end;
7048 }
7049
7050 ret = fwd;
7051 if (ret > len)
7052 ret = len;
7053
7054 if (ret) {
7055 struct hlua_flt_ctx *flt_ctx = filter->ctx;
7056
7057 FLT_OFF(filter, msg->chn) += ret;
7058 flt_ctx->cur_off[CHN_IDX(msg->chn)] += ret;
7059 flt_ctx->cur_len[CHN_IDX(msg->chn)] -= ret;
7060 }
7061
7062 end:
7063 lua_pushinteger(L, ret);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007064 return 1;
7065}
7066
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007067/* Set EOM flag on the HTX message.
7068 *
7069 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7070 * really know how to do without this feature.
7071 */
7072__LJMP static int hlua_http_msg_set_eom(lua_State *L)
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007073{
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007074 struct http_msg *msg;
7075 struct htx *htx;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007076
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007077 MAY_LJMP(check_args(L, 1, "set_eom"));
7078 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7079 htx = htxbuf(&msg->chn->buf);
7080 htx->flags |= HTX_FL_EOM;
7081 return 0;
7082}
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02007083
Christopher Fauletdf97ac42020-02-26 16:57:19 +01007084/* Unset EOM flag on the HTX message.
7085 *
7086 * NOTE: Not sure it is a good idea to manipulate this flag but for now I don't
7087 * really know how to do without this feature.
7088 */
7089__LJMP static int hlua_http_msg_unset_eom(lua_State *L)
7090{
7091 struct http_msg *msg;
7092 struct htx *htx;
7093
7094 MAY_LJMP(check_args(L, 1, "set_eom"));
7095 msg = MAY_LJMP(hlua_checkhttpmsg(L, 1));
7096 htx = htxbuf(&msg->chn->buf);
7097 htx->flags &= ~HTX_FL_EOM;
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02007098 return 0;
7099}
7100
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007101/*
7102 *
7103 *
William Lallemand3956c4e2021-09-21 16:25:15 +02007104 * Class HTTPClient
7105 *
7106 *
7107 */
7108__LJMP static struct hlua_httpclient *hlua_checkhttpclient(lua_State *L, int ud)
7109{
7110 return MAY_LJMP(hlua_checkudata(L, ud, class_httpclient_ref));
7111}
7112
William Lallemandf77f1de2021-09-28 19:10:38 +02007113
7114/* stops the httpclient and ask it to kill itself */
7115__LJMP static int hlua_httpclient_gc(lua_State *L)
7116{
7117 struct hlua_httpclient *hlua_hc;
7118
7119 MAY_LJMP(check_args(L, 1, "__gc"));
7120
7121 hlua_hc = MAY_LJMP(hlua_checkhttpclient(L, 1));
7122
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007123 if (MT_LIST_DELETE(&hlua_hc->by_hlua)) {
7124 /* we won the race against hlua_httpclient_destroy_all() */
William Lallemandbb581422022-10-20 10:57:28 +02007125 httpclient_stop_and_destroy(hlua_hc->hc);
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007126 hlua_hc->hc = NULL;
7127 }
William Lallemandf77f1de2021-09-28 19:10:38 +02007128
7129 return 0;
7130}
7131
7132
William Lallemand3956c4e2021-09-21 16:25:15 +02007133__LJMP static int hlua_httpclient_new(lua_State *L)
7134{
7135 struct hlua_httpclient *hlua_hc;
7136 struct hlua *hlua;
7137
7138 /* Get hlua struct, or NULL if we execute from main lua state */
7139 hlua = hlua_gethlua(L);
7140 if (!hlua)
7141 return 0;
7142
7143 /* Check stack size. */
7144 if (!lua_checkstack(L, 3)) {
7145 hlua_pusherror(L, "httpclient: full stack");
7146 goto err;
7147 }
7148 /* Create the object: obj[0] = userdata. */
7149 lua_newtable(L);
7150 hlua_hc = MAY_LJMP(lua_newuserdata(L, sizeof(*hlua_hc)));
7151 lua_rawseti(L, -2, 0);
7152 memset(hlua_hc, 0, sizeof(*hlua_hc));
7153
7154 hlua_hc->hc = httpclient_new(hlua, 0, IST_NULL);
7155 if (!hlua_hc->hc)
7156 goto err;
7157
Aurelien DARRAGON3ffbf382023-02-09 17:02:57 +01007158 MT_LIST_APPEND(&hlua->hc_list, &hlua_hc->by_hlua);
William Lallemandbb581422022-10-20 10:57:28 +02007159
William Lallemand3956c4e2021-09-21 16:25:15 +02007160 /* Pop a class stream metatable and affect it to the userdata. */
7161 lua_rawgeti(L, LUA_REGISTRYINDEX, class_httpclient_ref);
7162 lua_setmetatable(L, -2);
7163
7164 return 1;
7165
7166 err:
7167 WILL_LJMP(lua_error(L));
7168 return 0;
7169}
7170
7171
7172/*
7173 * Callback of the httpclient, this callback wakes the lua task up, once the
7174 * httpclient receives some data
7175 *
7176 */
7177
William Lallemandbd5739e2021-10-28 15:41:38 +02007178static void hlua_httpclient_cb(struct httpclient *hc)
William Lallemand3956c4e2021-09-21 16:25:15 +02007179{
7180 struct hlua *hlua = hc->caller;
7181
7182 if (!hlua || !hlua->task)
7183 return;
7184
7185 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7186}
7187
7188/*
William Lallemandd7df73a2021-09-23 17:54:00 +02007189 * Fill the lua stack with headers from the httpclient response
7190 * This works the same way as the hlua_http_get_headers() function
7191 */
7192__LJMP static int hlua_httpclient_get_headers(lua_State *L, struct hlua_httpclient *hlua_hc)
7193{
7194 struct http_hdr *hdr;
7195
7196 lua_newtable(L);
7197
William Lallemandef574b22021-10-05 16:19:31 +02007198 for (hdr = hlua_hc->hc->res.hdrs; hdr && isttest(hdr->n); hdr++) {
William Lallemandd7df73a2021-09-23 17:54:00 +02007199 struct ist n, v;
7200 int len;
7201
7202 n = hdr->n;
7203 v = hdr->v;
7204
7205 /* Check for existing entry:
7206 * assume that the table is on the top of the stack, and
7207 * push the key in the stack, the function lua_gettable()
7208 * perform the lookup.
7209 */
7210
7211 lua_pushlstring(L, n.ptr, n.len);
7212 lua_gettable(L, -2);
7213
7214 switch (lua_type(L, -1)) {
7215 case LUA_TNIL:
7216 /* Table not found, create it. */
7217 lua_pop(L, 1); /* remove the nil value. */
7218 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
7219 lua_newtable(L); /* create and push empty table. */
7220 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7221 lua_rawseti(L, -2, 0); /* index header value (pop it). */
7222 lua_rawset(L, -3); /* index new table with header name (pop the values). */
7223 break;
7224
7225 case LUA_TTABLE:
7226 /* Entry found: push the value in the table. */
7227 len = lua_rawlen(L, -1);
7228 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
7229 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
7230 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
7231 break;
7232
7233 default:
7234 /* Other cases are errors. */
7235 hlua_pusherror(L, "internal error during the parsing of headers.");
7236 WILL_LJMP(lua_error(L));
7237 }
7238 }
7239 return 1;
7240}
7241
7242/*
William Lallemand746e6f32021-10-06 10:57:44 +02007243 * Allocate and return an array of http_hdr ist extracted from the <headers> lua table
7244 *
7245 * Caller must free the result
7246 */
7247struct http_hdr *hlua_httpclient_table_to_hdrs(lua_State *L)
7248{
7249 struct http_hdr hdrs[global.tune.max_http_hdr];
7250 struct http_hdr *result = NULL;
7251 uint32_t hdr_num = 0;
7252
7253 lua_pushnil(L);
7254 while (lua_next(L, -2) != 0) {
7255 struct ist name, value;
7256 const char *n, *v;
7257 size_t nlen, vlen;
7258
7259 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
7260 /* Skip element if the key is not a string or if the value is not a table */
7261 goto next_hdr;
7262 }
7263
7264 n = lua_tolstring(L, -2, &nlen);
7265 name = ist2(n, nlen);
7266
7267 /* Loop on header's values */
7268 lua_pushnil(L);
7269 while (lua_next(L, -2)) {
7270 if (!lua_isstring(L, -1)) {
7271 /* Skip the value if it is not a string */
7272 goto next_value;
7273 }
7274
7275 v = lua_tolstring(L, -1, &vlen);
7276 value = ist2(v, vlen);
7277 name = ist2(n, nlen);
7278
7279 hdrs[hdr_num].n = istdup(name);
7280 hdrs[hdr_num].v = istdup(value);
7281
7282 hdr_num++;
7283
7284 next_value:
7285 lua_pop(L, 1);
7286 }
7287
7288 next_hdr:
7289 lua_pop(L, 1);
7290
7291 }
7292
7293 if (hdr_num) {
7294 /* alloc and copy the headers in the httpclient struct */
Tim Duesterhus16cc16d2021-11-06 15:14:45 +01007295 result = calloc((hdr_num + 1), sizeof(*result));
William Lallemand746e6f32021-10-06 10:57:44 +02007296 if (!result)
7297 goto skip_headers;
7298 memcpy(result, hdrs, sizeof(struct http_hdr) * (hdr_num + 1));
7299
7300 result[hdr_num].n = IST_NULL;
7301 result[hdr_num].v = IST_NULL;
7302 }
7303
7304skip_headers:
William Lallemand746e6f32021-10-06 10:57:44 +02007305
7306 return result;
7307}
7308
7309
William Lallemandbd5739e2021-10-28 15:41:38 +02007310/*
7311 * For each yield, checks if there is some data in the httpclient and push them
7312 * in the lua buffer, once the httpclient finished its job, push the result on
7313 * the stack
7314 */
7315__LJMP static int hlua_httpclient_rcv_yield(lua_State *L, int status, lua_KContext ctx)
7316{
7317 struct buffer *tr;
7318 int res;
7319 struct hlua *hlua = hlua_gethlua(L);
7320 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7321
7322
7323 tr = get_trash_chunk();
7324
7325 res = httpclient_res_xfer(hlua_hc->hc, tr);
7326 luaL_addlstring(&hlua_hc->b, b_orig(tr), res);
7327
7328 if (!httpclient_data(hlua_hc->hc) && httpclient_ended(hlua_hc->hc)) {
7329
7330 luaL_pushresult(&hlua_hc->b);
7331 lua_settable(L, -3);
7332
7333 lua_pushstring(L, "status");
7334 lua_pushinteger(L, hlua_hc->hc->res.status);
7335 lua_settable(L, -3);
7336
7337
7338 lua_pushstring(L, "reason");
7339 lua_pushlstring(L, hlua_hc->hc->res.reason.ptr, hlua_hc->hc->res.reason.len);
7340 lua_settable(L, -3);
7341
7342 lua_pushstring(L, "headers");
7343 hlua_httpclient_get_headers(L, hlua_hc);
7344 lua_settable(L, -3);
7345
7346 return 1;
7347 }
7348
7349 if (httpclient_data(hlua_hc->hc))
7350 task_wakeup(hlua->task, TASK_WOKEN_MSG);
7351
7352 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7353
7354 return 0;
7355}
7356
7357/*
7358 * Call this when trying to stream a body during a request
7359 */
7360__LJMP static int hlua_httpclient_snd_yield(lua_State *L, int status, lua_KContext ctx)
7361{
7362 struct hlua *hlua;
7363 struct hlua_httpclient *hlua_hc = hlua_checkhttpclient(L, 1);
7364 const char *body_str = NULL;
7365 int ret;
7366 int end = 0;
7367 size_t buf_len;
7368 size_t to_send = 0;
7369
7370 hlua = hlua_gethlua(L);
7371
7372 if (!hlua || !hlua->task)
7373 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7374 "'frontend', 'backend' or 'task'"));
7375
7376 ret = lua_getfield(L, -1, "body");
7377 if (ret != LUA_TSTRING)
7378 goto rcv;
7379
7380 body_str = lua_tolstring(L, -1, &buf_len);
7381 lua_pop(L, 1);
7382
Christopher Fauletfc591292022-01-12 14:46:03 +01007383 to_send = buf_len - hlua_hc->sent;
William Lallemandbd5739e2021-10-28 15:41:38 +02007384
7385 if ((hlua_hc->sent + to_send) >= buf_len)
7386 end = 1;
7387
7388 /* the end flag is always set since we are using the whole remaining size */
7389 hlua_hc->sent += httpclient_req_xfer(hlua_hc->hc, ist2(body_str + hlua_hc->sent, to_send), end);
7390
7391 if (buf_len > hlua_hc->sent) {
7392 /* still need to process the buffer */
7393 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
7394 } else {
7395 goto rcv;
7396 /* we sent the whole request buffer we can recv */
7397 }
7398 return 0;
7399
7400rcv:
7401
7402 /* we return a "res" object */
7403 lua_newtable(L);
7404
William Lallemandbd5739e2021-10-28 15:41:38 +02007405 lua_pushstring(L, "body");
William Lallemandd1187eb2021-11-02 10:40:06 +01007406 luaL_buffinit(L, &hlua_hc->b);
William Lallemandbd5739e2021-10-28 15:41:38 +02007407
William Lallemand933fe392021-11-04 09:45:58 +01007408 task_wakeup(hlua->task, TASK_WOKEN_MSG);
William Lallemandbd5739e2021-10-28 15:41:38 +02007409 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_rcv_yield, TICK_ETERNITY, 0));
7410
7411 return 1;
7412}
William Lallemand746e6f32021-10-06 10:57:44 +02007413
William Lallemand3956c4e2021-09-21 16:25:15 +02007414/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007415 * Send an HTTP request and wait for a response
William Lallemand3956c4e2021-09-21 16:25:15 +02007416 */
7417
William Lallemanddc2cc902021-10-26 11:43:26 +02007418__LJMP static int hlua_httpclient_send(lua_State *L, enum http_meth_t meth)
William Lallemand3956c4e2021-09-21 16:25:15 +02007419{
7420 struct hlua_httpclient *hlua_hc;
William Lallemand746e6f32021-10-06 10:57:44 +02007421 struct http_hdr *hdrs = NULL;
7422 struct http_hdr *hdrs_i = NULL;
William Lallemand3956c4e2021-09-21 16:25:15 +02007423 struct hlua *hlua;
William Lallemand746e6f32021-10-06 10:57:44 +02007424 const char *url_str = NULL;
William Lallemanddec25c32021-10-25 19:48:37 +02007425 const char *body_str = NULL;
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007426 size_t buf_len = 0;
William Lallemand746e6f32021-10-06 10:57:44 +02007427 int ret;
William Lallemand3956c4e2021-09-21 16:25:15 +02007428
7429 hlua = hlua_gethlua(L);
7430
7431 if (!hlua || !hlua->task)
7432 WILL_LJMP(luaL_error(L, "The 'get' function is only allowed in "
7433 "'frontend', 'backend' or 'task'"));
7434
William Lallemand746e6f32021-10-06 10:57:44 +02007435 if (lua_gettop(L) != 2 || lua_type(L, -1) != LUA_TTABLE)
7436 WILL_LJMP(luaL_error(L, "'get' needs a table as argument"));
7437
William Lallemand4f4f2b72022-02-17 20:00:23 +01007438 hlua_hc = hlua_checkhttpclient(L, 1);
7439
William Lallemand7177a952022-03-03 15:33:12 +01007440 lua_pushnil(L); /* first key */
7441 while (lua_next(L, 2)) {
7442 if (strcmp(lua_tostring(L, -2), "dst") == 0) {
7443 if (httpclient_set_dst(hlua_hc->hc, lua_tostring(L, -1)) < 0)
7444 WILL_LJMP(luaL_error(L, "Can't use the 'dst' argument"));
William Lallemand4f4f2b72022-02-17 20:00:23 +01007445
William Lallemand7177a952022-03-03 15:33:12 +01007446 } else if (strcmp(lua_tostring(L, -2), "url") == 0) {
7447 if (lua_type(L, -1) != LUA_TSTRING)
7448 WILL_LJMP(luaL_error(L, "invalid parameter in 'url', must be a string"));
7449 url_str = lua_tostring(L, -1);
William Lallemand3956c4e2021-09-21 16:25:15 +02007450
William Lallemand7177a952022-03-03 15:33:12 +01007451 } else if (strcmp(lua_tostring(L, -2), "timeout") == 0) {
7452 if (lua_type(L, -1) != LUA_TNUMBER)
7453 WILL_LJMP(luaL_error(L, "invalid parameter in 'timeout', must be a number"));
7454 httpclient_set_timeout(hlua_hc->hc, lua_tointeger(L, -1));
William Lallemandb4a4ef62022-02-23 14:18:16 +01007455
William Lallemand7177a952022-03-03 15:33:12 +01007456 } else if (strcmp(lua_tostring(L, -2), "headers") == 0) {
7457 if (lua_type(L, -1) != LUA_TTABLE)
7458 WILL_LJMP(luaL_error(L, "invalid parameter in 'headers', must be a table"));
7459 hdrs = hlua_httpclient_table_to_hdrs(L);
William Lallemand79416cb2021-09-24 14:51:44 +02007460
William Lallemand7177a952022-03-03 15:33:12 +01007461 } else if (strcmp(lua_tostring(L, -2), "body") == 0) {
7462 if (lua_type(L, -1) != LUA_TSTRING)
7463 WILL_LJMP(luaL_error(L, "invalid parameter in 'body', must be a string"));
7464 body_str = lua_tolstring(L, -1, &buf_len);
William Lallemandbd5739e2021-10-28 15:41:38 +02007465
William Lallemand7177a952022-03-03 15:33:12 +01007466 } else {
7467 WILL_LJMP(luaL_error(L, "'%s' invalid parameter name", lua_tostring(L, -2)));
7468 }
7469 /* removes 'value'; keeps 'key' for next iteration */
7470 lua_pop(L, 1);
7471 }
William Lallemanddec25c32021-10-25 19:48:37 +02007472
William Lallemand746e6f32021-10-06 10:57:44 +02007473 if (!url_str) {
7474 WILL_LJMP(luaL_error(L, "'get' need a 'url' argument"));
7475 return 0;
7476 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007477
William Lallemand10a37362022-03-02 16:18:26 +01007478 hlua_hc->sent = 0;
William Lallemand3956c4e2021-09-21 16:25:15 +02007479
Aurelien DARRAGON03564072023-02-09 15:26:25 +01007480 istfree(&hlua_hc->hc->req.url);
William Lallemand3956c4e2021-09-21 16:25:15 +02007481 hlua_hc->hc->req.url = istdup(ist(url_str));
William Lallemanddc2cc902021-10-26 11:43:26 +02007482 hlua_hc->hc->req.meth = meth;
William Lallemand3956c4e2021-09-21 16:25:15 +02007483
7484 /* update the httpclient callbacks */
William Lallemandbd5739e2021-10-28 15:41:38 +02007485 hlua_hc->hc->ops.res_stline = hlua_httpclient_cb;
7486 hlua_hc->hc->ops.res_headers = hlua_httpclient_cb;
7487 hlua_hc->hc->ops.res_payload = hlua_httpclient_cb;
William Lallemand8f170c72022-03-15 10:52:07 +01007488 hlua_hc->hc->ops.res_end = hlua_httpclient_cb;
William Lallemand3956c4e2021-09-21 16:25:15 +02007489
William Lallemandbd5739e2021-10-28 15:41:38 +02007490 /* a body is available, it will use the request callback */
Christopher Faulet380ae9c2022-10-14 14:57:04 +02007491 if (body_str && buf_len) {
William Lallemandbd5739e2021-10-28 15:41:38 +02007492 hlua_hc->hc->ops.req_payload = hlua_httpclient_cb;
7493 }
William Lallemand3956c4e2021-09-21 16:25:15 +02007494
William Lallemandbd5739e2021-10-28 15:41:38 +02007495 ret = httpclient_req_gen(hlua_hc->hc, hlua_hc->hc->req.url, meth, hdrs, IST_NULL);
William Lallemand3956c4e2021-09-21 16:25:15 +02007496
William Lallemand746e6f32021-10-06 10:57:44 +02007497 /* free the temporary headers array */
7498 hdrs_i = hdrs;
7499 while (hdrs_i && isttest(hdrs_i->n)) {
7500 istfree(&hdrs_i->n);
7501 istfree(&hdrs_i->v);
7502 hdrs_i++;
7503 }
7504 ha_free(&hdrs);
7505
7506
William Lallemand6137a9e2021-10-26 15:01:53 +02007507 if (ret != ERR_NONE) {
7508 WILL_LJMP(luaL_error(L, "Can't generate the HTTP request"));
7509 return 0;
7510 }
7511
William Lallemandc2d3db42022-04-26 11:46:13 +02007512 if (!httpclient_start(hlua_hc->hc))
7513 WILL_LJMP(luaL_error(L, "couldn't start the httpclient"));
William Lallemand6137a9e2021-10-26 15:01:53 +02007514
William Lallemandbd5739e2021-10-28 15:41:38 +02007515 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_httpclient_snd_yield, TICK_ETERNITY, 0));
William Lallemand3956c4e2021-09-21 16:25:15 +02007516
William Lallemand3956c4e2021-09-21 16:25:15 +02007517 return 0;
7518}
7519
7520/*
William Lallemanddc2cc902021-10-26 11:43:26 +02007521 * Sends an HTTP HEAD request and wait for a response
7522 *
7523 * httpclient:head(url, headers, payload)
7524 */
7525__LJMP static int hlua_httpclient_head(lua_State *L)
7526{
7527 return hlua_httpclient_send(L, HTTP_METH_HEAD);
7528}
7529
7530/*
7531 * Send an HTTP GET request and wait for a response
7532 *
7533 * httpclient:get(url, headers, payload)
7534 */
7535__LJMP static int hlua_httpclient_get(lua_State *L)
7536{
7537 return hlua_httpclient_send(L, HTTP_METH_GET);
7538
7539}
7540
7541/*
7542 * Sends an HTTP PUT request and wait for a response
7543 *
7544 * httpclient:put(url, headers, payload)
7545 */
7546__LJMP static int hlua_httpclient_put(lua_State *L)
7547{
7548 return hlua_httpclient_send(L, HTTP_METH_PUT);
7549}
7550
7551/*
7552 * Send an HTTP POST request and wait for a response
7553 *
7554 * httpclient:post(url, headers, payload)
7555 */
7556__LJMP static int hlua_httpclient_post(lua_State *L)
7557{
7558 return hlua_httpclient_send(L, HTTP_METH_POST);
7559}
7560
7561
7562/*
7563 * Sends an HTTP DELETE request and wait for a response
7564 *
7565 * httpclient:delete(url, headers, payload)
7566 */
7567__LJMP static int hlua_httpclient_delete(lua_State *L)
7568{
7569 return hlua_httpclient_send(L, HTTP_METH_DELETE);
7570}
7571
7572/*
William Lallemand3956c4e2021-09-21 16:25:15 +02007573 *
7574 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007575 * Class TXN
7576 *
7577 *
7578 */
7579
7580/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02007581 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007582 */
7583__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
7584{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007585 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007586}
7587
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007588__LJMP static int hlua_set_var(lua_State *L)
7589{
7590 struct hlua_txn *htxn;
7591 const char *name;
7592 size_t len;
7593 struct sample smp;
7594
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007595 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7596 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007597
7598 /* It is useles to retrieve the stream, but this function
7599 * runs only in a stream context.
7600 */
7601 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7602 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7603
7604 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01007605 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007606 hlua_lua2smp(L, 3, &smp);
7607
7608 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01007609 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02007610
7611 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
7612 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
7613 else
7614 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
7615
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007616 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007617}
7618
Christopher Faulet85d79c92016-11-09 16:54:56 +01007619__LJMP static int hlua_unset_var(lua_State *L)
7620{
7621 struct hlua_txn *htxn;
7622 const char *name;
7623 size_t len;
7624 struct sample smp;
7625
7626 MAY_LJMP(check_args(L, 2, "unset_var"));
7627
7628 /* It is useles to retrieve the stream, but this function
7629 * runs only in a stream context.
7630 */
7631 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7632 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7633
7634 /* Unset the variable. */
7635 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02007636 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
7637 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01007638}
7639
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007640__LJMP static int hlua_get_var(lua_State *L)
7641{
7642 struct hlua_txn *htxn;
7643 const char *name;
7644 size_t len;
7645 struct sample smp;
7646
7647 MAY_LJMP(check_args(L, 2, "get_var"));
7648
7649 /* It is useles to retrieve the stream, but this function
7650 * runs only in a stream context.
7651 */
7652 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7653 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
7654
Willy Tarreau7560dd42016-03-10 16:28:58 +01007655 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreaue352b9d2021-09-03 11:52:38 +02007656 if (!vars_get_by_name(name, len, &smp, NULL)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02007657 lua_pushnil(L);
7658 return 1;
7659 }
7660
7661 return hlua_smp2lua(L, &smp);
7662}
7663
Willy Tarreau59551662015-03-10 14:23:13 +01007664__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007665{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007666 struct hlua *hlua;
7667
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007668 MAY_LJMP(check_args(L, 2, "set_priv"));
7669
Willy Tarreau87b09662015-04-03 00:22:06 +02007670 /* It is useles to retrieve the stream, but this function
7671 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007672 */
7673 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007674
7675 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007676 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007677 if (!hlua)
7678 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007679
7680 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02007681 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007682
7683 /* Get and store new value. */
7684 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
7685 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
7686
7687 return 0;
7688}
7689
Willy Tarreau59551662015-03-10 14:23:13 +01007690__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007691{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007692 struct hlua *hlua;
7693
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007694 MAY_LJMP(check_args(L, 1, "get_priv"));
7695
Willy Tarreau87b09662015-04-03 00:22:06 +02007696 /* It is useles to retrieve the stream, but this function
7697 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007698 */
7699 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007700
7701 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01007702 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007703 if (!hlua) {
7704 lua_pushnil(L);
7705 return 1;
7706 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01007707
7708 /* Push configuration index in the stack. */
7709 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
7710
7711 return 1;
7712}
7713
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007714/* Create stack entry containing a class TXN. This function
7715 * return 0 if the stack does not contains free slots,
7716 * otherwise it returns 1.
7717 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007718static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007719{
Willy Tarreaude491382015-04-06 11:04:28 +02007720 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007721
7722 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007723 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007724 return 0;
7725
7726 /* NOTE: The allocation never fails. The failure
7727 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007728 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007729 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007730 /* Create the object: obj[0] = userdata. */
7731 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02007732 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01007733 lua_rawseti(L, -2, 0);
7734
Willy Tarreaude491382015-04-06 11:04:28 +02007735 htxn->s = s;
7736 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01007737 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02007738 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007739
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007740 /* Create the "f" field that contains a list of fetches. */
7741 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007742 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007743 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007744 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007745
7746 /* Create the "sf" field that contains a list of stringsafe fetches. */
7747 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01007748 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007749 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007750 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01007751
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007752 /* Create the "c" field that contains a list of converters. */
7753 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02007754 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007755 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007756 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01007757
7758 /* Create the "sc" field that contains a list of stringsafe converters. */
7759 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01007760 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007761 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007762 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01007763
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007764 /* Create the "req" field that contains the request channel object. */
7765 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007766 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007767 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007768 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007769
7770 /* Create the "res" field that contains the response channel object. */
7771 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01007772 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007773 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007774 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01007775
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007776 /* Creates the HTTP object is the current proxy allows http. */
7777 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01007778 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02007779 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007780 return 0;
7781 }
7782 else
7783 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02007784 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01007785
Christopher Faulet78c35472020-02-26 17:14:08 +01007786 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX) {
7787 /* HTTPMessage object are created when a lua TXN is created from
7788 * a filter context only
7789 */
7790
7791 /* Creates the HTTP-Request object is the current proxy allows http. */
7792 lua_pushstring(L, "http_req");
7793 if (p->mode == PR_MODE_HTTP) {
7794 if (!hlua_http_msg_new(L, &s->txn->req))
7795 return 0;
7796 }
7797 else
7798 lua_pushnil(L);
7799 lua_rawset(L, -3);
7800
7801 /* Creates the HTTP-Response object is the current proxy allows http. */
7802 lua_pushstring(L, "http_res");
7803 if (p->mode == PR_MODE_HTTP) {
7804 if (!hlua_http_msg_new(L, &s->txn->rsp))
7805 return 0;
7806 }
7807 else
7808 lua_pushnil(L);
7809 lua_rawset(L, -3);
7810 }
7811
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01007812 /* Pop a class sesison metatable and affect it to the userdata. */
7813 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
7814 lua_setmetatable(L, -2);
7815
7816 return 1;
7817}
7818
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01007819__LJMP static int hlua_txn_deflog(lua_State *L)
7820{
7821 const char *msg;
7822 struct hlua_txn *htxn;
7823
7824 MAY_LJMP(check_args(L, 2, "deflog"));
7825 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7826 msg = MAY_LJMP(luaL_checkstring(L, 2));
7827
7828 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
7829 return 0;
7830}
7831
7832__LJMP static int hlua_txn_log(lua_State *L)
7833{
7834 int level;
7835 const char *msg;
7836 struct hlua_txn *htxn;
7837
7838 MAY_LJMP(check_args(L, 3, "log"));
7839 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7840 level = MAY_LJMP(luaL_checkinteger(L, 2));
7841 msg = MAY_LJMP(luaL_checkstring(L, 3));
7842
7843 if (level < 0 || level >= NB_LOG_LEVELS)
7844 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
7845
7846 hlua_sendlog(htxn->s->be, level, msg);
7847 return 0;
7848}
7849
7850__LJMP static int hlua_txn_log_debug(lua_State *L)
7851{
7852 const char *msg;
7853 struct hlua_txn *htxn;
7854
7855 MAY_LJMP(check_args(L, 2, "Debug"));
7856 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7857 msg = MAY_LJMP(luaL_checkstring(L, 2));
7858 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
7859 return 0;
7860}
7861
7862__LJMP static int hlua_txn_log_info(lua_State *L)
7863{
7864 const char *msg;
7865 struct hlua_txn *htxn;
7866
7867 MAY_LJMP(check_args(L, 2, "Info"));
7868 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7869 msg = MAY_LJMP(luaL_checkstring(L, 2));
7870 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
7871 return 0;
7872}
7873
7874__LJMP static int hlua_txn_log_warning(lua_State *L)
7875{
7876 const char *msg;
7877 struct hlua_txn *htxn;
7878
7879 MAY_LJMP(check_args(L, 2, "Warning"));
7880 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7881 msg = MAY_LJMP(luaL_checkstring(L, 2));
7882 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
7883 return 0;
7884}
7885
7886__LJMP static int hlua_txn_log_alert(lua_State *L)
7887{
7888 const char *msg;
7889 struct hlua_txn *htxn;
7890
7891 MAY_LJMP(check_args(L, 2, "Alert"));
7892 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7893 msg = MAY_LJMP(luaL_checkstring(L, 2));
7894 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
7895 return 0;
7896}
7897
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007898__LJMP static int hlua_txn_set_loglevel(lua_State *L)
7899{
7900 struct hlua_txn *htxn;
7901 int ll;
7902
7903 MAY_LJMP(check_args(L, 2, "set_loglevel"));
7904 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7905 ll = MAY_LJMP(luaL_checkinteger(L, 2));
7906
7907 if (ll < 0 || ll > 7)
7908 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
7909
7910 htxn->s->logs.level = ll;
7911 return 0;
7912}
7913
7914__LJMP static int hlua_txn_set_tos(lua_State *L)
7915{
7916 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007917 int tos;
7918
7919 MAY_LJMP(check_args(L, 2, "set_tos"));
7920 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7921 tos = MAY_LJMP(luaL_checkinteger(L, 2));
7922
Willy Tarreau1a18b542018-12-11 16:37:42 +01007923 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007924 return 0;
7925}
7926
7927__LJMP static int hlua_txn_set_mark(lua_State *L)
7928{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007929 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007930 int mark;
7931
7932 MAY_LJMP(check_args(L, 2, "set_mark"));
7933 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7934 mark = MAY_LJMP(luaL_checkinteger(L, 2));
7935
Lukas Tribus579e3e32019-08-11 18:03:45 +02007936 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01007937 return 0;
7938}
7939
Patrick Hemmer268a7072018-05-11 12:52:31 -04007940__LJMP static int hlua_txn_set_priority_class(lua_State *L)
7941{
7942 struct hlua_txn *htxn;
7943
7944 MAY_LJMP(check_args(L, 2, "set_priority_class"));
7945 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7946 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
7947 return 0;
7948}
7949
7950__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
7951{
7952 struct hlua_txn *htxn;
7953
7954 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
7955 htxn = MAY_LJMP(hlua_checktxn(L, 1));
7956 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
7957 return 0;
7958}
7959
Christopher Faulet700d9e82020-01-31 12:21:52 +01007960/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007961 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01007962 * message and terminate the transaction. It returns 1 on success and 0 on
7963 * error. The Reply must be on top of the stack.
7964 */
7965__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
7966{
7967 struct htx *htx;
7968 struct htx_sl *sl;
7969 struct h1m h1m;
7970 const char *status, *reason, *body;
7971 size_t status_len, reason_len, body_len;
7972 int ret, code, flags;
7973
7974 code = 200;
7975 status = "200";
7976 status_len = 3;
7977 ret = lua_getfield(L, -1, "status");
7978 if (ret == LUA_TNUMBER) {
7979 code = lua_tointeger(L, -1);
7980 status = lua_tolstring(L, -1, &status_len);
7981 }
7982 lua_pop(L, 1);
7983
7984 reason = http_get_reason(code);
7985 reason_len = strlen(reason);
7986 ret = lua_getfield(L, -1, "reason");
7987 if (ret == LUA_TSTRING)
7988 reason = lua_tolstring(L, -1, &reason_len);
7989 lua_pop(L, 1);
7990
7991 body = NULL;
7992 body_len = 0;
7993 ret = lua_getfield(L, -1, "body");
7994 if (ret == LUA_TSTRING)
7995 body = lua_tolstring(L, -1, &body_len);
7996 lua_pop(L, 1);
7997
7998 /* Prepare the response before inserting the headers */
7999 h1m_init_res(&h1m);
8000 htx = htx_from_buf(&s->res.buf);
8001 channel_htx_truncate(&s->res, htx);
8002 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
8003 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
8004 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
8005 ist2(status, status_len), ist2(reason, reason_len));
8006 }
8007 else {
8008 flags = HTX_SL_F_IS_RESP;
8009 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
8010 ist2(status, status_len), ist2(reason, reason_len));
8011 }
8012 if (!sl)
8013 goto fail;
8014 sl->info.res.status = code;
8015
8016 /* Push in the stack the "headers" entry. */
8017 ret = lua_getfield(L, -1, "headers");
8018 if (ret != LUA_TTABLE)
8019 goto skip_headers;
8020
8021 lua_pushnil(L);
8022 while (lua_next(L, -2) != 0) {
8023 struct ist name, value;
8024 const char *n, *v;
8025 size_t nlen, vlen;
8026
8027 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
8028 /* Skip element if the key is not a string or if the value is not a table */
8029 goto next_hdr;
8030 }
8031
8032 n = lua_tolstring(L, -2, &nlen);
8033 name = ist2(n, nlen);
8034 if (isteqi(name, ist("content-length"))) {
8035 /* Always skip content-length header. It will be added
8036 * later with the correct len
8037 */
8038 goto next_hdr;
8039 }
8040
8041 /* Loop on header's values */
8042 lua_pushnil(L);
8043 while (lua_next(L, -2)) {
8044 if (!lua_isstring(L, -1)) {
8045 /* Skip the value if it is not a string */
8046 goto next_value;
8047 }
8048
8049 v = lua_tolstring(L, -1, &vlen);
8050 value = ist2(v, vlen);
8051
8052 if (isteqi(name, ist("transfer-encoding")))
8053 h1_parse_xfer_enc_header(&h1m, value);
8054 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
8055 goto fail;
8056
8057 next_value:
8058 lua_pop(L, 1);
8059 }
8060
8061 next_hdr:
8062 lua_pop(L, 1);
8063 }
8064 skip_headers:
8065 lua_pop(L, 1);
8066
8067 /* Update h1m flags: CLEN is set if CHNK is not present */
8068 if (!(h1m.flags & H1_MF_CHNK)) {
8069 const char *clen = ultoa(body_len);
8070
8071 h1m.flags |= H1_MF_CLEN;
8072 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
8073 goto fail;
8074 }
8075 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
8076 h1m.flags |= H1_MF_XFER_LEN;
8077
8078 /* Update HTX start-line flags */
8079 if (h1m.flags & H1_MF_XFER_ENC)
8080 flags |= HTX_SL_F_XFER_ENC;
8081 if (h1m.flags & H1_MF_XFER_LEN) {
8082 flags |= HTX_SL_F_XFER_LEN;
8083 if (h1m.flags & H1_MF_CHNK)
8084 flags |= HTX_SL_F_CHNK;
8085 else if (h1m.flags & H1_MF_CLEN)
8086 flags |= HTX_SL_F_CLEN;
8087 if (h1m.body_len == 0)
8088 flags |= HTX_SL_F_BODYLESS;
8089 }
8090 sl->flags |= flags;
8091
8092
8093 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008094 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01008095 goto fail;
8096
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01008097 htx->flags |= HTX_FL_EOM;
8098
Christopher Faulet700d9e82020-01-31 12:21:52 +01008099 /* Now, forward the response and terminate the transaction */
8100 s->txn->status = code;
8101 htx_to_buf(htx, &s->res.buf);
8102 if (!http_forward_proxy_resp(s, 1))
8103 goto fail;
8104
8105 return 1;
8106
8107 fail:
8108 channel_htx_truncate(&s->res, htx);
8109 return 0;
8110}
8111
8112/* Terminate a transaction if called from a lua action. For TCP streams,
8113 * processing is just aborted. Nothing is returned to the client and all
8114 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
8115 * is forwarded to the client before terminating the transaction. On success,
8116 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
8117 * with ACT_RET_ERR code. If this function is not called from a lua action, it
8118 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008119 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008120__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008121{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008122 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01008123 struct stream *s;
8124 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008125
Willy Tarreaub2ccb562015-04-06 11:11:15 +02008126 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008127
Christopher Faulet700d9e82020-01-31 12:21:52 +01008128 /* If the flags NOTERM is set, we cannot terminate the session, so we
8129 * just end the execution of the current lua code. */
8130 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008131 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02008132
Christopher Faulet700d9e82020-01-31 12:21:52 +01008133 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008134 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008135 struct channel *req = &s->req;
8136 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01008137
Christopher Faulet700d9e82020-01-31 12:21:52 +01008138 channel_auto_read(req);
8139 channel_abort(req);
8140 channel_auto_close(req);
8141 channel_erase(req);
8142
Christopher Faulet700d9e82020-01-31 12:21:52 +01008143 channel_auto_read(res);
8144 channel_auto_close(res);
8145 channel_shutr_now(res);
8146
8147 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
8148 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008149 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02008150
Christopher Faulet700d9e82020-01-31 12:21:52 +01008151 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
8152 /* No reply or invalid reply */
8153 s->txn->status = 0;
8154 http_reply_and_close(s, 0, NULL);
8155 }
8156 else {
8157 /* Remove extra args to have the reply on top of the stack */
8158 if (lua_gettop(L) > 2)
8159 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008160
Christopher Faulet700d9e82020-01-31 12:21:52 +01008161 if (!hlua_txn_forward_reply(L, s)) {
8162 if (!(s->flags & SF_ERR_MASK))
8163 s->flags |= SF_ERR_PRXCOND;
8164 lua_pushinteger(L, ACT_RET_ERR);
8165 WILL_LJMP(hlua_done(L));
8166 return 0; /* Never reached */
8167 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02008168 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008169
Christopher Faulet700d9e82020-01-31 12:21:52 +01008170 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
8171 if (htxn->dir == SMP_OPT_DIR_REQ) {
8172 /* let's log the request time */
8173 s->logs.tv_request = now;
8174 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02008175 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008176 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008177
Christopher Faulet700d9e82020-01-31 12:21:52 +01008178 done:
8179 if (!(s->flags & SF_ERR_MASK))
8180 s->flags |= SF_ERR_LOCAL;
8181 if (!(s->flags & SF_FINST_MASK))
8182 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02008183
Christopher Faulete48d1dc2021-08-13 14:11:17 +02008184 if ((htxn->flags & HLUA_TXN_CTX_MASK) == HLUA_TXN_FLT_CTX)
8185 lua_pushinteger(L, -1);
8186 else
8187 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02008188 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008189 return 0;
8190}
8191
Christopher Faulet700d9e82020-01-31 12:21:52 +01008192/*
8193 *
8194 *
8195 * Class REPLY
8196 *
8197 *
8198 */
8199
8200/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
8201 * free slots, the function fails and returns 0;
8202 */
8203static int hlua_txn_reply_new(lua_State *L)
8204{
8205 struct hlua_txn *htxn;
8206 const char *reason, *body = NULL;
8207 int ret, status;
8208
8209 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01008210 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01008211 hlua_pusherror(L, "txn object is not an HTTP transaction.");
8212 WILL_LJMP(lua_error(L));
8213 }
8214
8215 /* Default value */
8216 status = 200;
8217 reason = http_get_reason(status);
8218
8219 if (lua_istable(L, 2)) {
8220 /* load status and reason from the table argument at index 2 */
8221 ret = lua_getfield(L, 2, "status");
8222 if (ret == LUA_TNIL)
8223 goto reason;
8224 else if (ret != LUA_TNUMBER) {
8225 /* invalid status: ignore the reason */
8226 goto body;
8227 }
8228 status = lua_tointeger(L, -1);
8229
8230 reason:
8231 lua_pop(L, 1); /* restore the stack: remove status */
8232 ret = lua_getfield(L, 2, "reason");
8233 if (ret == LUA_TSTRING)
8234 reason = lua_tostring(L, -1);
8235
8236 body:
8237 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
8238 ret = lua_getfield(L, 2, "body");
8239 if (ret == LUA_TSTRING)
8240 body = lua_tostring(L, -1);
8241 lua_pop(L, 1); /* restore the stack: remove body */
8242 }
8243
8244 /* Create the Reply table */
8245 lua_newtable(L);
8246
8247 /* Add status element */
8248 lua_pushstring(L, "status");
8249 lua_pushinteger(L, status);
8250 lua_settable(L, -3);
8251
8252 /* Add reason element */
8253 reason = http_get_reason(status);
8254 lua_pushstring(L, "reason");
8255 lua_pushstring(L, reason);
8256 lua_settable(L, -3);
8257
8258 /* Add body element, nil if undefined */
8259 lua_pushstring(L, "body");
8260 if (body)
8261 lua_pushstring(L, body);
8262 else
8263 lua_pushnil(L);
8264 lua_settable(L, -3);
8265
8266 /* Add headers element */
8267 lua_pushstring(L, "headers");
8268 lua_newtable(L);
8269
8270 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8271 if (lua_istable(L, 2)) {
8272 /* load headers from the table argument at index 2. If it is a table, copy it. */
8273 ret = lua_getfield(L, 2, "headers");
8274 if (ret == LUA_TTABLE) {
8275 /* stack: [ ... <headers:table>, <table> ] */
8276 lua_pushnil(L);
8277 while (lua_next(L, -2) != 0) {
8278 /* stack: [ ... <headers:table>, <table>, k, v] */
8279 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
8280 /* invalid value type, skip it */
8281 lua_pop(L, 1);
8282 continue;
8283 }
8284
8285
8286 /* Duplicate the key and swap it with the value. */
8287 lua_pushvalue(L, -2);
8288 lua_insert(L, -2);
8289 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
8290
8291 lua_newtable(L);
8292 lua_insert(L, -2);
8293 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
8294
8295 if (lua_isstring(L, -1)) {
8296 /* push the value in the inner table */
8297 lua_rawseti(L, -2, 1);
8298 }
8299 else { /* table */
8300 lua_pushnil(L);
8301 while (lua_next(L, -2) != 0) {
8302 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
8303 if (!lua_isstring(L, -1)) {
8304 /* invalid value type, skip it*/
8305 lua_pop(L, 1);
8306 continue;
8307 }
8308 /* push the value in the inner table */
8309 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
8310 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
8311 }
8312 lua_pop(L, 1);
8313 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
8314 }
8315
8316 /* push (k,v) on the stack in the headers table:
8317 * stack: [ ... <headers:table>, <table>, k, k, v ]
8318 */
8319 lua_settable(L, -5);
8320 /* stack: [ ... <headers:table>, <table>, k ] */
8321 }
8322 }
8323 lua_pop(L, 1);
8324 }
8325 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
8326 lua_settable(L, -3);
8327 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
8328
8329 /* Pop a class sesison metatable and affect it to the userdata. */
8330 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
8331 lua_setmetatable(L, -2);
8332 return 1;
8333}
8334
8335/* Set the reply status code, and optionally the reason. If no reason is
8336 * provided, the default one corresponding to the status code is used.
8337 */
8338__LJMP static int hlua_txn_reply_set_status(lua_State *L)
8339{
8340 int status = MAY_LJMP(luaL_checkinteger(L, 2));
8341 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
8342
8343 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008344 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008345
8346 if (status < 100 || status > 599) {
8347 lua_pushboolean(L, 0);
8348 return 1;
8349 }
8350 if (!reason)
8351 reason = http_get_reason(status);
8352
8353 lua_pushinteger(L, status);
8354 lua_setfield(L, 1, "status");
8355
8356 lua_pushstring(L, reason);
8357 lua_setfield(L, 1, "reason");
8358
8359 lua_pushboolean(L, 1);
8360 return 1;
8361}
8362
8363/* Add a header into the reply object. Each header name is associated to an
8364 * array of values in the "headers" table. If the header name is not found, a
8365 * new entry is created.
8366 */
8367__LJMP static int hlua_txn_reply_add_header(lua_State *L)
8368{
8369 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8370 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
8371 int ret;
8372
8373 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008374 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008375
8376 /* Push in the stack the "headers" entry. */
8377 ret = lua_getfield(L, 1, "headers");
8378 if (ret != LUA_TTABLE) {
8379 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
8380 WILL_LJMP(lua_error(L));
8381 }
8382
8383 /* check if the header is already registered. If not, register it. */
8384 ret = lua_getfield(L, -1, name);
8385 if (ret == LUA_TNIL) {
8386 /* Entry not found. */
8387 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
8388
8389 /* Insert the new header name in the array in the top of the stack.
8390 * It left the new array in the top of the stack.
8391 */
8392 lua_newtable(L);
8393 lua_pushstring(L, name);
8394 lua_pushvalue(L, -2);
8395 lua_settable(L, -4);
8396 }
8397 else if (ret != LUA_TTABLE) {
8398 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
8399 WILL_LJMP(lua_error(L));
8400 }
8401
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008402 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01008403 * the header value as new entry.
8404 */
8405 lua_pushstring(L, value);
8406 ret = lua_rawlen(L, -2);
8407 lua_rawseti(L, -2, ret + 1);
8408
8409 lua_pushboolean(L, 1);
8410 return 1;
8411}
8412
8413/* Remove all occurrences of a given header name. */
8414__LJMP static int hlua_txn_reply_del_header(lua_State *L)
8415{
8416 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
8417 int ret;
8418
8419 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008420 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008421
8422 /* Push in the stack the "headers" entry. */
8423 ret = lua_getfield(L, 1, "headers");
8424 if (ret != LUA_TTABLE) {
8425 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
8426 WILL_LJMP(lua_error(L));
8427 }
8428
8429 lua_pushstring(L, name);
8430 lua_pushnil(L);
8431 lua_settable(L, -3);
8432
8433 lua_pushboolean(L, 1);
8434 return 1;
8435}
8436
8437/* Set the reply's body. Overwrite any existing entry. */
8438__LJMP static int hlua_txn_reply_set_body(lua_State *L)
8439{
8440 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
8441
8442 /* First argument (self) must be a table */
Aurelien DARRAGONd83d0452022-10-05 11:46:45 +02008443 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
Christopher Faulet700d9e82020-01-31 12:21:52 +01008444
8445 lua_pushstring(L, payload);
8446 lua_setfield(L, 1, "body");
8447
8448 lua_pushboolean(L, 1);
8449 return 1;
8450}
8451
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008452__LJMP static int hlua_log(lua_State *L)
8453{
8454 int level;
8455 const char *msg;
8456
8457 MAY_LJMP(check_args(L, 2, "log"));
8458 level = MAY_LJMP(luaL_checkinteger(L, 1));
8459 msg = MAY_LJMP(luaL_checkstring(L, 2));
8460
8461 if (level < 0 || level >= NB_LOG_LEVELS)
8462 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
8463
8464 hlua_sendlog(NULL, level, msg);
8465 return 0;
8466}
8467
8468__LJMP static int hlua_log_debug(lua_State *L)
8469{
8470 const char *msg;
8471
8472 MAY_LJMP(check_args(L, 1, "debug"));
8473 msg = MAY_LJMP(luaL_checkstring(L, 1));
8474 hlua_sendlog(NULL, LOG_DEBUG, msg);
8475 return 0;
8476}
8477
8478__LJMP static int hlua_log_info(lua_State *L)
8479{
8480 const char *msg;
8481
8482 MAY_LJMP(check_args(L, 1, "info"));
8483 msg = MAY_LJMP(luaL_checkstring(L, 1));
8484 hlua_sendlog(NULL, LOG_INFO, msg);
8485 return 0;
8486}
8487
8488__LJMP static int hlua_log_warning(lua_State *L)
8489{
8490 const char *msg;
8491
8492 MAY_LJMP(check_args(L, 1, "warning"));
8493 msg = MAY_LJMP(luaL_checkstring(L, 1));
8494 hlua_sendlog(NULL, LOG_WARNING, msg);
8495 return 0;
8496}
8497
8498__LJMP static int hlua_log_alert(lua_State *L)
8499{
8500 const char *msg;
8501
8502 MAY_LJMP(check_args(L, 1, "alert"));
8503 msg = MAY_LJMP(luaL_checkstring(L, 1));
8504 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01008505 return 0;
8506}
8507
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008508__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008509{
8510 int wakeup_ms = lua_tointeger(L, -1);
Willy Tarreau12c02702021-09-30 16:12:31 +02008511 if (!tick_is_expired(wakeup_ms, now_ms))
Willy Tarreau9635e032018-10-16 17:52:55 +02008512 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008513 return 0;
8514}
8515
8516__LJMP static int hlua_sleep(lua_State *L)
8517{
8518 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008519 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008520
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008521 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008522
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008523 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008524 wakeup_ms = tick_add(now_ms, delay);
8525 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008526
Willy Tarreau9635e032018-10-16 17:52:55 +02008527 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008528 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008529}
8530
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008531__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008532{
8533 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008534 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008535
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008536 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008537
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008538 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008539 wakeup_ms = tick_add(now_ms, delay);
8540 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008541
Willy Tarreau9635e032018-10-16 17:52:55 +02008542 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008543 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008544}
8545
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008546/* This functionis an LUA binding. it permits to give back
8547 * the hand at the HAProxy scheduler. It is used when the
8548 * LUA processing consumes a lot of time.
8549 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01008550__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008551{
8552 return 0;
8553}
8554
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008555__LJMP static int hlua_yield(lua_State *L)
8556{
Willy Tarreau9635e032018-10-16 17:52:55 +02008557 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01008558 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008559}
8560
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008561/* This function change the nice of the currently executed
8562 * task. It is used set low or high priority at the current
8563 * task.
8564 */
Willy Tarreau59551662015-03-10 14:23:13 +01008565__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008566{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008567 struct hlua *hlua;
8568 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008569
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008570 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008571 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008572
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008573 /* Get hlua struct, or NULL if we execute from main lua state */
8574 hlua = hlua_gethlua(L);
8575
8576 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008577 if (!hlua || !hlua->task)
8578 return 0;
8579
8580 if (nice < -1024)
8581 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008582 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01008583 nice = 1024;
8584
8585 hlua->task->nice = nice;
8586 return 0;
8587}
8588
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008589/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008590 * HAProxy task subsystem when the task is awaked. The LUA runtime can
8591 * return an E_AGAIN signal, the emmiter of this signal must set a
8592 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008593 *
8594 * Task wrapper are longjmp safe because the only one Lua code
8595 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008596 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01008597struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008598{
Olivier Houchard9f6af332018-05-25 14:04:04 +02008599 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008600 enum hlua_exec status;
8601
Willy Tarreau6ef52f42022-06-15 14:19:48 +02008602 if (task->tid < 0)
8603 task->tid = tid;
8604
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008605 /* If it is the first call to the task, we must initialize the
8606 * execution timeouts.
8607 */
8608 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02008609 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008610
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008611 /* Execute the Lua code. */
8612 status = hlua_ctx_resume(hlua, 1);
8613
8614 switch (status) {
8615 /* finished or yield */
8616 case HLUA_E_OK:
8617 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008618 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02008619 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008620 break;
8621
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01008622 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01008623 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02008624 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008625 break;
8626
8627 /* finished with error. */
Aurelien DARRAGON79544102022-11-24 14:27:15 +01008628 case HLUA_E_ETMOUT:
8629 SEND_ERR(NULL, "Lua task: execution timeout.\n");
8630 goto err_task_abort;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008631 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008632 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Aurelien DARRAGON79544102022-11-24 14:27:15 +01008633 goto err_task_abort;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008634 case HLUA_E_ERR:
8635 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008636 SEND_ERR(NULL, "Lua task: unknown error.\n");
Aurelien DARRAGON79544102022-11-24 14:27:15 +01008637 err_task_abort:
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008638 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02008639 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02008640 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008641 break;
8642 }
Emeric Brun253e53e2017-10-17 18:58:40 +02008643 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008644}
8645
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008646/* This function is an LUA binding that register LUA function to be
8647 * executed after the HAProxy configuration parsing and before the
8648 * HAProxy scheduler starts. This function expect only one LUA
8649 * argument that is a function. This function returns nothing, but
8650 * throws if an error is encountered.
8651 */
8652__LJMP static int hlua_register_init(lua_State *L)
8653{
8654 struct hlua_init_function *init;
8655 int ref;
8656
8657 MAY_LJMP(check_args(L, 1, "register_init"));
8658
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01008659 if (hlua_gethlua(L)) {
8660 /* runtime processing */
8661 WILL_LJMP(luaL_error(L, "register_init: not available outside of body context"));
8662 }
8663
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008664 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8665
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008666 init = calloc(1, sizeof(*init));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008667 if (!init) {
8668 hlua_unref(L, ref);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008669 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008670 }
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008671
8672 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02008673 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008674 return 0;
8675}
8676
Ilya Shipitsin6f86eaa2022-11-30 16:22:42 +05008677/* This function is an LUA binding. It permits to register a task
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008678 * executed in parallel of the main HAroxy activity. The task is
8679 * created and it is set in the HAProxy scheduler. It can be called
8680 * from the "init" section, "post init" or during the runtime.
8681 *
8682 * Lua prototype:
8683 *
8684 * <none> core.register_task(<function>)
8685 */
8686static int hlua_register_task(lua_State *L)
8687{
Christopher Faulet5294ec02021-04-12 12:24:47 +02008688 struct hlua *hlua = NULL;
8689 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008690 int ref;
Thierry Fournier021d9862020-11-28 23:42:03 +01008691 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008692
8693 MAY_LJMP(check_args(L, 1, "register_task"));
8694
8695 ref = MAY_LJMP(hlua_checkfunction(L, 1));
8696
Thierry Fournier75fc0292020-11-28 13:18:56 +01008697 /* Get the reference state. If the reference is NULL, L is the master
8698 * state, otherwise hlua->T is.
8699 */
8700 hlua = hlua_gethlua(L);
8701 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01008702 /* we are in runtime processing */
8703 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008704 else
Thierry Fournier021d9862020-11-28 23:42:03 +01008705 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01008706 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01008707
Willy Tarreaubafbe012017-11-24 17:34:44 +01008708 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008709 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008710 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008711 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008712
Thierry Fournier59f11be2020-11-29 00:37:41 +01008713 /* We are in the common lua state, execute the task anywhere,
8714 * otherwise, inherit the current thread identifier
8715 */
8716 if (state_id == 0)
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008717 task = task_new_anywhere();
Thierry Fournier59f11be2020-11-29 00:37:41 +01008718 else
Willy Tarreaubeeabf52021-10-01 18:23:30 +02008719 task = task_new_here();
Willy Tarreaue09101e2018-10-16 17:37:12 +02008720 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02008721 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02008722
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008723 task->context = hlua;
8724 task->process = hlua_process_task;
8725
Thierry Fournier021d9862020-11-28 23:42:03 +01008726 if (!hlua_ctx_init(hlua, state_id, task, 1))
Christopher Faulet5294ec02021-04-12 12:24:47 +02008727 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008728
8729 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01008730 hlua_pushref(hlua->T, ref);
Aurelien DARRAGONbe58d662023-03-13 14:09:21 +01008731 /* function ref not needed anymore since it was pushed to the substack */
8732 hlua_unref(L, ref);
8733
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008734 hlua->nargs = 0;
8735
8736 /* Schedule task. */
Willy Tarreaue3957f82021-09-30 16:17:37 +02008737 task_wakeup(task, TASK_WOKEN_INIT);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008738
8739 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02008740
8741 alloc_error:
8742 task_destroy(task);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01008743 hlua_unref(L, ref);
Christopher Faulet5294ec02021-04-12 12:24:47 +02008744 hlua_ctx_destroy(hlua);
8745 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8746 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008747}
8748
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008749/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
8750 * doesn't allow "yield" functions because the HAProxy engine cannot
8751 * resume converters.
8752 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008753static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008754{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008755 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008756 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008757 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008758
Willy Tarreaube508f12016-03-10 11:47:01 +01008759 if (!stream)
8760 return 0;
8761
Willy Tarreau87b09662015-04-03 00:22:06 +02008762 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008763 * Lua context can be not initialized. This behavior
8764 * permits to save performances because a systematic
8765 * Lua initialization cause 5% performances loss.
8766 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008767 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008768 struct hlua *hlua;
8769
8770 hlua = pool_alloc(pool_head_hlua);
8771 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008772 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
8773 return 0;
8774 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008775 HLUA_INIT(hlua);
8776 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01008777 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008778 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
8779 return 0;
8780 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008781 }
8782
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008783 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008784 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008785
8786 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008787 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008788 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
8789 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01008790 else
8791 error = "critical error";
8792 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008793 return 0;
8794 }
8795
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008796 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008797 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008798 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008799 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008800 return 0;
8801 }
8802
8803 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01008804 hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008805
8806 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008807 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008808 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008809 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008810 return 0;
8811 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008812 hlua_smp2lua(stream->hlua->T, smp);
8813 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008814
8815 /* push keywords in the stack. */
8816 if (arg_p) {
8817 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008818 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008819 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008820 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008821 return 0;
8822 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008823 hlua_arg2lua(stream->hlua->T, arg_p);
8824 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008825 }
8826 }
8827
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008828 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008829 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008830
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008831 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008832 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008833 }
8834
8835 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008836 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008837 /* finished. */
8838 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02008839 /* If the stack is empty, the function fails. */
8840 if (lua_gettop(stream->hlua->T) <= 0)
8841 return 0;
8842
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008843 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008844 hlua_lua2smp(stream->hlua->T, -1, smp);
8845 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008846 return 1;
8847
8848 /* yield. */
8849 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008850 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008851 return 0;
8852
8853 /* finished with error. */
8854 case HLUA_E_ERRMSG:
8855 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008856 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008857 fcn->name, lua_tostring(stream->hlua->T, -1));
8858 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008859 return 0;
8860
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008861 case HLUA_E_ETMOUT:
8862 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
8863 return 0;
8864
8865 case HLUA_E_NOMEM:
8866 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
8867 return 0;
8868
8869 case HLUA_E_YIELD:
8870 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
8871 return 0;
8872
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008873 case HLUA_E_ERR:
8874 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008875 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01008876 __fallthrough;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008877
8878 default:
8879 return 0;
8880 }
8881}
8882
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008883/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
8884 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01008885 * resume sample-fetches. This function will be called by the sample
8886 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008887 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02008888static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
8889 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008890{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008891 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02008892 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008893 const char *error;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02008894 unsigned int hflags = HLUA_TXN_NOTERM | HLUA_TXN_SMP_CTX;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008895
Willy Tarreaube508f12016-03-10 11:47:01 +01008896 if (!stream)
8897 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01008898
Willy Tarreau87b09662015-04-03 00:22:06 +02008899 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008900 * Lua context can be not initialized. This behavior
8901 * permits to save performances because a systematic
8902 * Lua initialization cause 5% performances loss.
8903 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008904 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008905 struct hlua *hlua;
8906
8907 hlua = pool_alloc(pool_head_hlua);
8908 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008909 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
8910 return 0;
8911 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01008912 hlua->T = NULL;
8913 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01008914 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008915 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
8916 return 0;
8917 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01008918 }
8919
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008920 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008921 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008922
8923 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008924 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008925 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
8926 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01008927 else
8928 error = "critical error";
8929 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008930 return 0;
8931 }
8932
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008933 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008934 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008935 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008936 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008937 return 0;
8938 }
8939
8940 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01008941 hlua_pushref(stream->hlua->T, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008942
8943 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02008944 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008945 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008946 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008947 return 0;
8948 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008949 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008950
8951 /* push keywords in the stack. */
8952 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
8953 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008954 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008955 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008956 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008957 return 0;
8958 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008959 hlua_arg2lua(stream->hlua->T, arg_p);
8960 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008961 }
8962
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008963 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008964 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008965
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008966 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008967 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008968 }
8969
8970 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008971 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008972 /* finished. */
8973 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02008974 /* If the stack is empty, the function fails. */
8975 if (lua_gettop(stream->hlua->T) <= 0)
8976 return 0;
8977
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008978 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008979 hlua_lua2smp(stream->hlua->T, -1, smp);
8980 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008981
8982 /* Set the end of execution flag. */
8983 smp->flags &= ~SMP_F_MAY_CHANGE;
8984 return 1;
8985
8986 /* yield. */
8987 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008988 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008989 return 0;
8990
8991 /* finished with error. */
8992 case HLUA_E_ERRMSG:
8993 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02008994 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01008995 fcn->name, lua_tostring(stream->hlua->T, -1));
8996 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008997 return 0;
8998
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008999 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009000 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
9001 return 0;
9002
9003 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009004 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
9005 return 0;
9006
9007 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009008 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
9009 return 0;
9010
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009011 case HLUA_E_ERR:
9012 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009013 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Willy Tarreau14de3952022-11-14 07:08:28 +01009014 __fallthrough;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009015
9016 default:
9017 return 0;
9018 }
9019}
9020
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009021/* This function is an LUA binding used for registering
9022 * "sample-conv" functions. It expects a converter name used
9023 * in the haproxy configuration file, and an LUA function.
9024 */
9025__LJMP static int hlua_register_converters(lua_State *L)
9026{
9027 struct sample_conv_kw_list *sck;
9028 const char *name;
9029 int ref;
9030 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02009031 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009032 struct sample_conv *sc;
9033 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009034
9035 MAY_LJMP(check_args(L, 2, "register_converters"));
9036
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01009037 if (hlua_gethlua(L)) {
9038 /* runtime processing */
9039 WILL_LJMP(luaL_error(L, "register_converters: not available outside of body context"));
9040 }
9041
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009042 /* First argument : converter name. */
9043 name = MAY_LJMP(luaL_checkstring(L, 1));
9044
9045 /* Second argument : lua function. */
9046 ref = MAY_LJMP(hlua_checkfunction(L, 2));
9047
Thierry Fournierf67442e2020-11-28 20:41:07 +01009048 /* Check if the converter is already registered */
9049 trash = get_trash_chunk();
9050 chunk_printf(trash, "lua.%s", name);
9051 sc = find_sample_conv(trash->area, trash->data);
9052 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01009053 fcn = sc->private;
9054 if (fcn->function_ref[hlua_state_id] != -1) {
9055 ha_warning("Trying to register converter 'lua.%s' more than once. "
9056 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009057 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +01009058 }
9059 fcn->function_ref[hlua_state_id] = ref;
9060 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009061 }
9062
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009063 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009064 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009065 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +02009066 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01009067 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009068 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +02009069 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009070
9071 /* Fill fcn. */
9072 fcn->name = strdup(name);
9073 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +02009074 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009075 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009076
9077 /* List head */
9078 sck->list.n = sck->list.p = NULL;
9079
9080 /* converter keyword. */
9081 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009082 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009083 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +02009084 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009085
9086 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
9087 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01009088 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 +01009089 sck->kw[0].val_args = NULL;
9090 sck->kw[0].in_type = SMP_T_STR;
9091 sck->kw[0].out_type = SMP_T_STR;
9092 sck->kw[0].private = fcn;
9093
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009094 /* Register this new converter */
9095 sample_register_convs(sck);
9096
9097 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +02009098
9099 alloc_error:
9100 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009101 hlua_unref(L, ref);
Christopher Fauletaa224302021-04-12 14:08:21 +02009102 ha_free(&sck);
9103 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9104 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01009105}
9106
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009107/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009108 * "sample-fetch" functions. It expects a converter name used
9109 * in the haproxy configuration file, and an LUA function.
9110 */
9111__LJMP static int hlua_register_fetches(lua_State *L)
9112{
9113 const char *name;
9114 int ref;
9115 int len;
9116 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +02009117 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009118 struct sample_fetch *sf;
9119 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009120
9121 MAY_LJMP(check_args(L, 2, "register_fetches"));
9122
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01009123 if (hlua_gethlua(L)) {
9124 /* runtime processing */
9125 WILL_LJMP(luaL_error(L, "register_fetches: not available outside of body context"));
9126 }
9127
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009128 /* First argument : sample-fetch name. */
9129 name = MAY_LJMP(luaL_checkstring(L, 1));
9130
9131 /* Second argument : lua function. */
9132 ref = MAY_LJMP(hlua_checkfunction(L, 2));
9133
Thierry Fournierf67442e2020-11-28 20:41:07 +01009134 /* Check if the sample-fetch is already registered */
9135 trash = get_trash_chunk();
9136 chunk_printf(trash, "lua.%s", name);
9137 sf = find_sample_fetch(trash->area, trash->data);
9138 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01009139 fcn = sf->private;
9140 if (fcn->function_ref[hlua_state_id] != -1) {
9141 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
9142 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009143 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +01009144 }
9145 fcn->function_ref[hlua_state_id] = ref;
9146 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009147 }
9148
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009149 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009150 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009151 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +02009152 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01009153 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009154 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +02009155 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009156
9157 /* Fill fcn. */
9158 fcn->name = strdup(name);
9159 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +02009160 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01009161 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009162
9163 /* List head */
9164 sfk->list.n = sfk->list.p = NULL;
9165
9166 /* sample-fetch keyword. */
9167 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009168 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009169 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +02009170 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009171
9172 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
9173 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01009174 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 +01009175 sfk->kw[0].val_args = NULL;
9176 sfk->kw[0].out_type = SMP_T_STR;
9177 sfk->kw[0].use = SMP_USE_HTTP_ANY;
9178 sfk->kw[0].val = 0;
9179 sfk->kw[0].private = fcn;
9180
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009181 /* Register this new fetch. */
9182 sample_register_fetches(sfk);
9183
9184 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +02009185
9186 alloc_error:
9187 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009188 hlua_unref(L, ref);
Christopher Faulet2567f182021-04-12 14:11:50 +02009189 ha_free(&sfk);
9190 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
9191 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01009192}
9193
Christopher Faulet501465d2020-02-26 14:54:16 +01009194/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009195 */
Christopher Faulet501465d2020-02-26 14:54:16 +01009196__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009197{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009198 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009199 unsigned int delay;
9200 unsigned int wakeup_ms;
9201
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009202 /* Get hlua struct, or NULL if we execute from main lua state */
9203 hlua = hlua_gethlua(L);
9204 if (!hlua) {
9205 return 0;
9206 }
9207
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009208 MAY_LJMP(check_args(L, 1, "wake_time"));
9209
9210 delay = MAY_LJMP(luaL_checkinteger(L, 1));
9211 wakeup_ms = tick_add(now_ms, delay);
9212 hlua->wake_time = wakeup_ms;
9213 return 0;
9214}
9215
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009216/* This function is a wrapper to execute each LUA function declared as an action
9217 * wrapper during the initialisation period. This function may return any
9218 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
9219 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
9220 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009221 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009222static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02009223 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009224{
9225 char **arg;
Christopher Faulet8c9e6bb2021-08-06 16:29:41 +02009226 unsigned int hflags = HLUA_TXN_ACT_CTX;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009227 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009228 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009229
9230 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01009231 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
9232 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
9233 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
9234 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009235 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009236 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009237 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009238 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009239
Willy Tarreau87b09662015-04-03 00:22:06 +02009240 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009241 * Lua context can be not initialized. This behavior
9242 * permits to save performances because a systematic
9243 * Lua initialization cause 5% performances loss.
9244 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009245 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009246 struct hlua *hlua;
9247
9248 hlua = pool_alloc(pool_head_hlua);
9249 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009250 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009251 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009252 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009253 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01009254 HLUA_INIT(hlua);
9255 s->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01009256 if (!hlua_ctx_init(s->hlua, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn), s->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009257 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009258 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009259 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009260 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01009261 }
9262
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009263 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009264 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009265
9266 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009267 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009268 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
9269 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01009270 else
9271 error = "critical error";
9272 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009273 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009274 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009275 }
9276
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009277 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009278 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009279 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009280 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009281 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009282 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009283 }
9284
9285 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009286 hlua_pushref(s->hlua->T, rule->arg.hlua_rule->fcn->function_ref[s->hlua->state_id]);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009287
Willy Tarreau87b09662015-04-03 00:22:06 +02009288 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02009289 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009290 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009291 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009292 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009293 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009294 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009295 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009296
9297 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009298 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009299 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009300 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009301 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009302 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009303 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009304 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009305 lua_pushstring(s->hlua->T, *arg);
9306 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009307 }
9308
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009309 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009310 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009311
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009312 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009313 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009314 }
9315
9316 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01009317 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009318 /* finished. */
9319 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009320 /* Catch the return value */
9321 if (lua_gettop(s->hlua->T) > 0)
9322 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009323
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009324 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02009325 if (act_ret == ACT_RET_YIELD) {
9326 if (flags & ACT_OPT_FINAL)
9327 goto err_yield;
9328
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009329 if (dir == SMP_OPT_DIR_REQ)
9330 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
9331 s->hlua->wake_time);
9332 else
9333 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
9334 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009335 }
9336 goto end;
9337
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009338 /* yield. */
9339 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01009340 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009341 if (dir == SMP_OPT_DIR_REQ)
9342 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
9343 s->hlua->wake_time);
9344 else
9345 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
9346 s->hlua->wake_time);
9347
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009348 /* Some actions can be wake up when a "write" event
9349 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009350 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009351 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02009352 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009353 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009354 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009355 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009356 act_ret = ACT_RET_YIELD;
9357 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009358
9359 /* finished with error. */
9360 case HLUA_E_ERRMSG:
9361 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009362 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009363 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01009364 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009365 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009366
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009367 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +01009368 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009369 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009370
9371 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +01009372 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009373 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009374
9375 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02009376 err_yield:
9377 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009378 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009379 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009380 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009381
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009382 case HLUA_E_ERR:
9383 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02009384 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009385 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009386
9387 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009388 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009389 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009390
9391 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02009392 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02009393 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01009394 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009395}
9396
Willy Tarreau144f84a2021-03-02 16:09:26 +01009397struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009398{
Olivier Houchard9f6af332018-05-25 14:04:04 +02009399 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009400
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009401 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02009402 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02009403 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009404}
9405
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009406static int hlua_applet_tcp_init(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009407{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009408 struct hlua_tcp_ctx *tcp_ctx = applet_reserve_svcctx(ctx, sizeof(*tcp_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +02009409 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009410 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009411 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009412 struct task *task;
9413 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009414 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009415
Willy Tarreaubafbe012017-11-24 17:34:44 +01009416 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009417 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009418 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009419 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009420 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009421 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009422 HLUA_INIT(hlua);
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009423 tcp_ctx->hlua = hlua;
9424 tcp_ctx->flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009425
9426 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +02009427 task = task_new_here();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009428 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009429 SEND_ERR(strm->be, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009430 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009431 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009432 }
9433 task->nice = 0;
9434 task->context = ctx;
9435 task->process = hlua_applet_wakeup;
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009436 tcp_ctx->task = task;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009437
9438 /* In the execution wrappers linked with a stream, the
9439 * Lua context can be not initialized. This behavior
9440 * permits to save performances because a systematic
9441 * Lua initialization cause 5% performances loss.
9442 */
Thierry Fournierc7492592020-11-28 23:57:24 +01009443 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009444 SEND_ERR(strm->be, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009445 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009446 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009447 }
9448
9449 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02009450 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009451
9452 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009453 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01009454 if (lua_type(hlua->T, -1) == LUA_TSTRING)
9455 error = lua_tostring(hlua->T, -1);
9456 else
9457 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009458 SEND_ERR(strm->be, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009459 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +02009460 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009461 }
9462
9463 /* Check stack available size. */
9464 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009465 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009466 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009467 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009468 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009469 }
9470
9471 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009472 hlua_pushref(hlua->T, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009473
9474 /* Create and and push object stream in the stack. */
9475 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009476 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009477 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009478 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009479 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009480 }
9481 hlua->nargs = 1;
9482
9483 /* push keywords in the stack. */
9484 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
9485 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009486 SEND_ERR(strm->be, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009487 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009488 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009489 return -1;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009490 }
9491 lua_pushstring(hlua->T, *arg);
9492 hlua->nargs++;
9493 }
9494
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009495 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009496
9497 /* Wakeup the applet ASAP. */
Willy Tarreau90e8b452022-05-25 18:21:43 +02009498 applet_need_more_data(ctx);
Willy Tarreau4164eb92022-05-25 15:42:03 +02009499 applet_have_more_data(ctx);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009500
Christopher Fauletc9929382022-05-12 11:52:27 +02009501 return 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009502}
9503
Willy Tarreau60409db2019-08-21 14:14:50 +02009504void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009505{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009506 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02009507 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009508 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009509 struct act_rule *rule = ctx->rule;
9510 struct proxy *px = strm->be;
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009511 struct hlua *hlua = tcp_ctx->hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009512
Christopher Faulet31572222023-03-31 11:13:48 +02009513 if (unlikely(se_fl_test(ctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
9514 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009515
Christopher Faulet31572222023-03-31 11:13:48 +02009516 /* The applet execution is already done. */
9517 if (tcp_ctx->flags & APPLET_DONE)
9518 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009519
9520 /* Execute the function. */
9521 switch (hlua_ctx_resume(hlua, 1)) {
9522 /* finished. */
9523 case HLUA_E_OK:
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009524 tcp_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +02009525 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
9526 break;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009527
9528 /* yield. */
9529 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01009530 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009531 task_schedule(tcp_ctx->task, hlua->wake_time);
Christopher Faulet31572222023-03-31 11:13:48 +02009532 break;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009533
9534 /* finished with error. */
9535 case HLUA_E_ERRMSG:
9536 /* Display log. */
9537 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009538 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009539 lua_pop(hlua->T, 1);
9540 goto error;
9541
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009542 case HLUA_E_ETMOUT:
9543 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009544 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009545 goto error;
9546
9547 case HLUA_E_NOMEM:
9548 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009549 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009550 goto error;
9551
9552 case HLUA_E_YIELD: /* unexpected */
9553 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009554 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02009555 goto error;
9556
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009557 case HLUA_E_ERR:
9558 /* Display log. */
9559 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009560 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009561 goto error;
9562
9563 default:
9564 goto error;
9565 }
9566
Christopher Faulet31572222023-03-31 11:13:48 +02009567out:
9568 /* eat the whole request */
9569 co_skip(sc_oc(sc), co_data(sc_oc(sc)));
9570 return;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009571
Christopher Faulet31572222023-03-31 11:13:48 +02009572error:
9573 se_fl_set(ctx->sedesc, SE_FL_ERROR);
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009574 tcp_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +02009575 goto out;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009576}
9577
9578static void hlua_applet_tcp_release(struct appctx *ctx)
9579{
Willy Tarreaue23f33b2022-05-06 14:07:13 +02009580 struct hlua_tcp_ctx *tcp_ctx = ctx->svcctx;
9581
9582 task_destroy(tcp_ctx->task);
9583 tcp_ctx->task = NULL;
9584 hlua_ctx_destroy(tcp_ctx->hlua);
9585 tcp_ctx->hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009586}
9587
Christopher Fauletc9929382022-05-12 11:52:27 +02009588/* The function returns 0 if the initialisation is complete or -1 if
9589 * an errors occurs. It also reserves the appctx for an hlua_http_ctx.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009590 */
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009591static int hlua_applet_http_init(struct appctx *ctx)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009592{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009593 struct hlua_http_ctx *http_ctx = applet_reserve_svcctx(ctx, sizeof(*http_ctx));
Willy Tarreauc12b3212022-05-27 11:08:15 +02009594 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009595 struct stream *strm = __sc_strm(sc);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009596 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009597 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009598 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009599 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009600 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009601
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009602 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01009603 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009604 if (!hlua) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009605 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009606 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009607 return -1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01009608 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009609 HLUA_INIT(hlua);
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009610 http_ctx->hlua = hlua;
9611 http_ctx->left_bytes = -1;
9612 http_ctx->flags = 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009613
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01009614 if (txn->req.flags & HTTP_MSGF_VER_11)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009615 http_ctx->flags |= APPLET_HTTP11;
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01009616
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009617 /* Create task used by signal to wakeup applets. */
Willy Tarreaubeeabf52021-10-01 18:23:30 +02009618 task = task_new_here();
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009619 if (!task) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009620 SEND_ERR(strm->be, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009621 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009622 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009623 }
9624 task->nice = 0;
9625 task->context = ctx;
9626 task->process = hlua_applet_wakeup;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009627 http_ctx->task = task;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009628
9629 /* In the execution wrappers linked with a stream, the
9630 * Lua context can be not initialized. This behavior
9631 * permits to save performances because a systematic
9632 * Lua initialization cause 5% performances loss.
9633 */
Thierry Fournierc7492592020-11-28 23:57:24 +01009634 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009635 SEND_ERR(strm->be, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009636 ctx->rule->arg.hlua_rule->fcn->name);
Christopher Fauletc9929382022-05-12 11:52:27 +02009637 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009638 }
9639
9640 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02009641 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009642
9643 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009644 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01009645 if (lua_type(hlua->T, -1) == LUA_TSTRING)
9646 error = lua_tostring(hlua->T, -1);
9647 else
9648 error = "critical error";
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009649 SEND_ERR(strm->be, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009650 ctx->rule->arg.hlua_rule->fcn->name, error);
Christopher Fauletc9929382022-05-12 11:52:27 +02009651 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009652 }
9653
9654 /* Check stack available size. */
9655 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009656 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009657 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009658 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009659 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009660 }
9661
9662 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +01009663 hlua_pushref(hlua->T, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009664
9665 /* Create and and push object stream in the stack. */
9666 if (!hlua_applet_http_new(hlua->T, ctx)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009667 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009668 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009669 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009670 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009671 }
9672 hlua->nargs = 1;
9673
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009674 /* push keywords in the stack. */
9675 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
9676 if (!lua_checkstack(hlua->T, 1)) {
Christopher Faulet4aa1d282022-01-13 16:01:35 +01009677 SEND_ERR(strm->be, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01009678 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009679 RESET_SAFE_LJMP(hlua);
Christopher Fauletc9929382022-05-12 11:52:27 +02009680 return -1;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009681 }
9682 lua_pushstring(hlua->T, *arg);
9683 hlua->nargs++;
9684 }
9685
Thierry Fournier7cbe5042020-11-28 17:02:21 +01009686 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009687
9688 /* Wakeup the applet when data is ready for read. */
Willy Tarreau90e8b452022-05-25 18:21:43 +02009689 applet_need_more_data(ctx);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009690
Christopher Fauletc9929382022-05-12 11:52:27 +02009691 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009692}
9693
Willy Tarreau60409db2019-08-21 14:14:50 +02009694void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009695{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009696 struct hlua_http_ctx *http_ctx = ctx->svcctx;
Willy Tarreauc12b3212022-05-27 11:08:15 +02009697 struct stconn *sc = appctx_sc(ctx);
Willy Tarreau3e7be362022-05-27 10:35:27 +02009698 struct stream *strm = __sc_strm(sc);
9699 struct channel *req = sc_oc(sc);
9700 struct channel *res = sc_ic(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009701 struct act_rule *rule = ctx->rule;
9702 struct proxy *px = strm->be;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009703 struct hlua *hlua = http_ctx->hlua;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009704 struct htx *req_htx, *res_htx;
9705
9706 res_htx = htx_from_buf(&res->buf);
9707
Christopher Faulet31572222023-03-31 11:13:48 +02009708 if (unlikely(se_fl_test(ctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
9709 goto out;
9710
9711 /* The applet execution is already done. */
9712 if (http_ctx->flags & APPLET_DONE)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009713 goto out;
9714
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009715 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009716 if (!b_size(&res->buf)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02009717 sc_need_room(sc);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009718 goto out;
9719 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009720
9721 /* Set the currently running flag. */
9722 if (!HLUA_IS_RUNNING(hlua) &&
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009723 !(http_ctx->flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +02009724 if (!co_data(req)) {
Willy Tarreau90e8b452022-05-25 18:21:43 +02009725 applet_need_more_data(ctx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009726 goto out;
9727 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009728 }
9729
Christopher Faulet31572222023-03-31 11:13:48 +02009730 /* Execute the function. */
9731 switch (hlua_ctx_resume(hlua, 1)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009732 /* finished. */
9733 case HLUA_E_OK:
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009734 http_ctx->flags |= APPLET_DONE;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009735 break;
9736
9737 /* yield. */
9738 case HLUA_E_AGAIN:
9739 if (hlua->wake_time != TICK_ETERNITY)
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009740 task_schedule(http_ctx->task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009741 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009742
9743 /* finished with error. */
9744 case HLUA_E_ERRMSG:
9745 /* Display log. */
9746 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Christopher Faulet31572222023-03-31 11:13:48 +02009747 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009748 lua_pop(hlua->T, 1);
9749 goto error;
9750
9751 case HLUA_E_ETMOUT:
9752 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Christopher Faulet31572222023-03-31 11:13:48 +02009753 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009754 goto error;
9755
9756 case HLUA_E_NOMEM:
9757 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Christopher Faulet31572222023-03-31 11:13:48 +02009758 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009759 goto error;
9760
9761 case HLUA_E_YIELD: /* unexpected */
9762 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Christopher Faulet31572222023-03-31 11:13:48 +02009763 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009764 goto error;
9765
9766 case HLUA_E_ERR:
9767 /* Display log. */
9768 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Christopher Faulet31572222023-03-31 11:13:48 +02009769 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009770 goto error;
9771
9772 default:
9773 goto error;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009774 }
9775
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009776 if (http_ctx->flags & APPLET_DONE) {
9777 if (http_ctx->flags & APPLET_RSP_SENT)
Christopher Faulet31572222023-03-31 11:13:48 +02009778 goto out;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01009779
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009780 if (!(http_ctx->flags & APPLET_HDR_SENT))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009781 goto error;
9782
Christopher Fauletf89af9c2022-04-07 10:07:18 +02009783 /* no more data are expected. If the response buffer is empty
9784 * for a chunked message, be sure to add something (EOT block in
9785 * this case) to have something to send. It is important to be
9786 * sure the EOM flags will be handled by the endpoint.
9787 */
9788 if (htx_is_empty(res_htx) && (strm->txn->rsp.flags & (HTTP_MSGF_XFER_LEN|HTTP_MSGF_CNT_LEN)) == HTTP_MSGF_XFER_LEN) {
9789 if (!htx_add_endof(res_htx, HTX_BLK_EOT)) {
Willy Tarreau3e7be362022-05-27 10:35:27 +02009790 sc_need_room(sc);
Christopher Fauletf89af9c2022-04-07 10:07:18 +02009791 goto out;
9792 }
9793 channel_add_input(res, 1);
9794 }
9795
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01009796 res_htx->flags |= HTX_FL_EOM;
Christopher Faulet31572222023-03-31 11:13:48 +02009797 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009798 strm->txn->status = http_ctx->status;
9799 http_ctx->flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009800 }
9801
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009802 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009803 htx_to_buf(res_htx, &res->buf);
Christopher Faulet31572222023-03-31 11:13:48 +02009804 /* eat the whole request */
9805 if (co_data(req)) {
9806 req_htx = htx_from_buf(&req->buf);
9807 co_htx_skip(req, req_htx, co_data(req));
9808 htx_to_buf(req_htx, &req->buf);
9809 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009810 return;
9811
9812 error:
9813
9814 /* If we are in HTTP mode, and we are not send any
9815 * data, return a 500 server error in best effort:
9816 * if there is no room available in the buffer,
9817 * just close the connection.
9818 */
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009819 if (!(http_ctx->flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02009820 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009821
9822 channel_erase(res);
9823 res->buf.data = b_data(err);
9824 memcpy(res->buf.area, b_head(err), b_data(err));
9825 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01009826 channel_add_input(res, res_htx->data);
Christopher Faulet31572222023-03-31 11:13:48 +02009827 se_fl_set(ctx->sedesc, SE_FL_EOI|SE_FL_EOS);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009828 }
Christopher Faulet31572222023-03-31 11:13:48 +02009829 else
9830 se_fl_set(ctx->sedesc, SE_FL_ERROR);
9831
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009832 if (!(strm->flags & SF_ERR_MASK))
9833 strm->flags |= SF_ERR_RESOURCE;
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009834 http_ctx->flags |= APPLET_DONE;
Christopher Faulet31572222023-03-31 11:13:48 +02009835 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01009836}
9837
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009838static void hlua_applet_http_release(struct appctx *ctx)
9839{
Willy Tarreauaa229cc2022-05-06 14:26:10 +02009840 struct hlua_http_ctx *http_ctx = ctx->svcctx;
9841
9842 task_destroy(http_ctx->task);
9843 http_ctx->task = NULL;
9844 hlua_ctx_destroy(http_ctx->hlua);
9845 http_ctx->hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009846}
9847
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009848/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009849 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009850 *
9851 * This function can fail with an abort() due to an Lua critical error.
9852 * We are in the configuration parsing process of HAProxy, this abort() is
9853 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009854 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009855static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
9856 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009857{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009858 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009859 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009860
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009861 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02009862 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009863 if (!rule->arg.hlua_rule) {
9864 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009865 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009866 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009867
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009868 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02009869 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
9870 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009871 if (!rule->arg.hlua_rule->args) {
9872 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009873 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009874 }
9875
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009876 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01009877 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009878
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009879 /* Expect some arguments */
9880 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01009881 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009882 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +02009883 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009884 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01009885 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009886 if (!rule->arg.hlua_rule->args[i]) {
9887 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02009888 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009889 }
9890 (*cur_arg)++;
9891 }
9892 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009893
Thierry FOURNIER42148732015-09-02 17:17:33 +02009894 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02009895 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02009896 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +02009897
9898 error:
9899 if (rule->arg.hlua_rule) {
9900 if (rule->arg.hlua_rule->args) {
9901 for (i = 0; i < fcn->nargs; i++)
9902 ha_free(&rule->arg.hlua_rule->args[i]);
9903 ha_free(&rule->arg.hlua_rule->args);
9904 }
9905 ha_free(&rule->arg.hlua_rule);
9906 }
9907 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01009908}
9909
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009910static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
9911 struct act_rule *rule, char **err)
9912{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02009913 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009914
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009915 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009916 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009917 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009918 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01009919 * the call of this analyzer.
9920 */
9921 if (rule->from != ACT_F_HTTP_REQ) {
9922 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
9923 return ACT_RET_PRS_ERR;
9924 }
9925
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009926 /* Memory for the rule. */
9927 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
9928 if (!rule->arg.hlua_rule) {
9929 memprintf(err, "out of memory error");
9930 return ACT_RET_PRS_ERR;
9931 }
9932
9933 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01009934 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009935
9936 /* TODO: later accept arguments. */
9937 rule->arg.hlua_rule->args = NULL;
9938
9939 /* Add applet pointer in the rule. */
9940 rule->applet.obj_type = OBJ_TYPE_APPLET;
9941 rule->applet.name = fcn->name;
9942 rule->applet.init = hlua_applet_http_init;
9943 rule->applet.fct = hlua_applet_http_fct;
9944 rule->applet.release = hlua_applet_http_release;
9945 rule->applet.timeout = hlua_timeout_applet;
9946
9947 return ACT_RET_PRS_OK;
9948}
9949
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009950/* This function is an LUA binding used for registering
9951 * "sample-conv" functions. It expects a converter name used
9952 * in the haproxy configuration file, and an LUA function.
9953 */
9954__LJMP static int hlua_register_action(lua_State *L)
9955{
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009956 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009957 const char *name;
9958 int ref;
9959 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02009960 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009961 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +01009962 struct buffer *trash;
9963 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009964
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009965 /* Initialise the number of expected arguments at 0. */
9966 nargs = 0;
9967
9968 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
9969 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009970
Aurelien DARRAGON87f52972023-02-24 09:43:54 +01009971 if (hlua_gethlua(L)) {
9972 /* runtime processing */
9973 WILL_LJMP(luaL_error(L, "register_action: not available outside of body context"));
9974 }
9975
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009976 /* First argument : converter name. */
9977 name = MAY_LJMP(luaL_checkstring(L, 1));
9978
9979 /* Second argument : environment. */
9980 if (lua_type(L, 2) != LUA_TTABLE)
9981 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
9982
9983 /* Third argument : lua function. */
9984 ref = MAY_LJMP(hlua_checkfunction(L, 3));
9985
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009986 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01009987 if (lua_gettop(L) >= 4)
9988 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
9989
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009990 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009991 lua_pushnil(L);
9992 while (lua_next(L, 2) != 0) {
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009993 if (lua_type(L, -1) != LUA_TSTRING) {
9994 hlua_unref(L, ref);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009995 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +01009996 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02009997
Thierry Fournierf67442e2020-11-28 20:41:07 +01009998 /* Check if action exists */
9999 trash = get_trash_chunk();
10000 chunk_printf(trash, "lua.%s", name);
10001 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
10002 akw = tcp_req_cont_action(trash->area);
10003 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
10004 akw = tcp_res_cont_action(trash->area);
10005 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
10006 akw = action_http_req_custom(trash->area);
10007 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
10008 akw = action_http_res_custom(trash->area);
10009 } else {
10010 akw = NULL;
10011 }
10012 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010013 fcn = akw->private;
10014 if (fcn->function_ref[hlua_state_id] != -1) {
10015 ha_warning("Trying to register action 'lua.%s' more than once. "
10016 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010017 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010018 }
10019 fcn->function_ref[hlua_state_id] = ref;
10020
10021 /* pop the environment string. */
10022 lua_pop(L, 1);
10023 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010024 }
10025
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010026 /* Check required environment. Only accepted "http" or "tcp". */
10027 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010028 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010029 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010030 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010031 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010032 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010033 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010034
10035 /* Fill fcn. */
10036 fcn->name = strdup(name);
10037 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010038 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +010010039 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010040
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -070010041 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +010010042 fcn->nargs = nargs;
10043
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010044 /* List head */
10045 akl->list.n = akl->list.p = NULL;
10046
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010047 /* action keyword. */
10048 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +020010049 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010050 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010051 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010052
10053 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
10054
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020010055 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010056 akl->kw[0].private = fcn;
10057 akl->kw[0].parse = action_register_lua;
10058
10059 /* select the action registering point. */
10060 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
10061 tcp_req_cont_keywords_register(akl);
10062 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
10063 tcp_res_cont_keywords_register(akl);
10064 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
10065 http_req_keywords_register(akl);
10066 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
10067 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010068 else {
10069 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010070 hlua_unref(L, ref);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010071 if (akl)
10072 ha_free((char **)&(akl->kw[0].kw));
10073 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010010074 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010075 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
10076 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010077 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010078
10079 /* pop the environment string. */
10080 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010081
10082 /* reset for next loop */
10083 akl = NULL;
10084 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010085 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010086 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010087
10088 alloc_error:
10089 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010090 hlua_unref(L, ref);
Christopher Faulet4fc9da02021-04-12 15:08:12 +020010091 ha_free(&akl);
10092 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10093 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010094}
10095
10096static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
10097 struct act_rule *rule, char **err)
10098{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +020010099 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010100
Christopher Faulet280f85b2019-07-15 15:02:04 +020010101 if (px->mode == PR_MODE_HTTP) {
10102 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +010010103 return ACT_RET_PRS_ERR;
10104 }
10105
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010106 /* Memory for the rule. */
10107 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
10108 if (!rule->arg.hlua_rule) {
10109 memprintf(err, "out of memory error");
10110 return ACT_RET_PRS_ERR;
10111 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010112
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010113 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +010010114 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010115
10116 /* TODO: later accept arguments. */
10117 rule->arg.hlua_rule->args = NULL;
10118
10119 /* Add applet pointer in the rule. */
10120 rule->applet.obj_type = OBJ_TYPE_APPLET;
10121 rule->applet.name = fcn->name;
10122 rule->applet.init = hlua_applet_tcp_init;
10123 rule->applet.fct = hlua_applet_tcp_fct;
10124 rule->applet.release = hlua_applet_tcp_release;
10125 rule->applet.timeout = hlua_timeout_applet;
10126
10127 return 0;
10128}
10129
10130/* This function is an LUA binding used for registering
10131 * "sample-conv" functions. It expects a converter name used
10132 * in the haproxy configuration file, and an LUA function.
10133 */
10134__LJMP static int hlua_register_service(lua_State *L)
10135{
10136 struct action_kw_list *akl;
10137 const char *name;
10138 const char *env;
10139 int ref;
10140 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010141 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010142 struct buffer *trash;
10143 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010144
10145 MAY_LJMP(check_args(L, 3, "register_service"));
10146
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010010147 if (hlua_gethlua(L)) {
10148 /* runtime processing */
10149 WILL_LJMP(luaL_error(L, "register_service: not available outside of body context"));
10150 }
10151
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010152 /* First argument : converter name. */
10153 name = MAY_LJMP(luaL_checkstring(L, 1));
10154
10155 /* Second argument : environment. */
10156 env = MAY_LJMP(luaL_checkstring(L, 2));
10157
10158 /* Third argument : lua function. */
10159 ref = MAY_LJMP(hlua_checkfunction(L, 3));
10160
Thierry Fournierf67442e2020-11-28 20:41:07 +010010161 /* Check for service already registered */
10162 trash = get_trash_chunk();
10163 chunk_printf(trash, "lua.%s", name);
10164 akw = service_find(trash->area);
10165 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010166 fcn = akw->private;
10167 if (fcn->function_ref[hlua_state_id] != -1) {
10168 ha_warning("Trying to register service 'lua.%s' more than once. "
10169 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010170 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010171 }
10172 fcn->function_ref[hlua_state_id] = ref;
10173 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010174 }
10175
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010176 /* Allocate and fill the sample fetch keyword struct. */
10177 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
10178 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010179 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010180 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010181 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010182 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010183
10184 /* Fill fcn. */
10185 len = strlen("<lua.>") + strlen(name) + 1;
10186 fcn->name = calloc(1, len);
10187 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010188 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010189 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +010010190 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010191
10192 /* List head */
10193 akl->list.n = akl->list.p = NULL;
10194
10195 /* converter keyword. */
10196 len = strlen("lua.") + strlen(name) + 1;
10197 akl->kw[0].kw = calloc(1, len);
10198 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +020010199 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010200
10201 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
10202
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +010010203 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010204 if (strcmp(env, "tcp") == 0)
10205 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020010206 else if (strcmp(env, "http") == 0)
10207 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010208 else {
10209 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010210 hlua_unref(L, ref);
Christopher Faulet5c028d72021-04-12 15:11:44 +020010211 if (akl)
10212 ha_free((char **)&(akl->kw[0].kw));
10213 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +010010214 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +010010215 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +020010216 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010217
Amaury Denoyellee4a617c2021-05-06 15:33:09 +020010218 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020010219 akl->kw[0].private = fcn;
10220
10221 /* End of array. */
10222 memset(&akl->kw[1], 0, sizeof(*akl->kw));
10223
10224 /* Register this new converter */
10225 service_keywords_register(akl);
10226
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010227 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +020010228
10229 alloc_error:
10230 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010231 hlua_unref(L, ref);
Christopher Faulet5c028d72021-04-12 15:11:44 +020010232 ha_free(&akl);
10233 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
10234 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +020010235}
10236
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010237/* This function initialises Lua cli handler. It copies the
10238 * arguments in the Lua stack and create channel IO objects.
10239 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +020010240static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010241{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010242 struct hlua_cli_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010243 struct hlua *hlua;
10244 struct hlua_function *fcn;
10245 int i;
10246 const char *error;
10247
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010248 fcn = private;
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010249 ctx->fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010250
Willy Tarreaubafbe012017-11-24 17:34:44 +010010251 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010252 if (!hlua) {
10253 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010254 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +010010255 }
10256 HLUA_INIT(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010257 ctx->hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010258
10259 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +050010260 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010261 * applet_http. It is absolutely compatible.
10262 */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010263 ctx->task = task_new_here();
10264 if (!ctx->task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +010010265 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010266 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010267 }
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010268 ctx->task->nice = 0;
10269 ctx->task->context = appctx;
10270 ctx->task->process = hlua_applet_wakeup;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010271
10272 /* Initialises the Lua context */
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010273 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), ctx->task, 0)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010274 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +010010275 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010276 }
10277
10278 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010279 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010280 if (lua_type(hlua->T, -1) == LUA_TSTRING)
10281 error = lua_tostring(hlua->T, -1);
10282 else
10283 error = "critical error";
10284 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
10285 goto error;
10286 }
10287
10288 /* Check stack available size. */
10289 if (!lua_checkstack(hlua->T, 2)) {
10290 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10291 goto error;
10292 }
10293
10294 /* Restore the function in the stack. */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010295 hlua_pushref(hlua->T, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010296
10297 /* Once the arguments parsed, the CLI is like an AppletTCP,
10298 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010299 */
10300 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
10301 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10302 goto error;
10303 }
10304 hlua->nargs = 1;
10305
10306 /* push keywords in the stack. */
10307 for (i = 0; *args[i]; i++) {
10308 /* Check stack available size. */
10309 if (!lua_checkstack(hlua->T, 1)) {
10310 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
10311 goto error;
10312 }
10313 lua_pushstring(hlua->T, args[i]);
10314 hlua->nargs++;
10315 }
10316
10317 /* We must initialize the execution timeouts. */
10318 hlua->max_time = hlua_timeout_session;
10319
10320 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010321 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010322
10323 /* It's ok */
10324 return 0;
10325
10326 /* It's not ok. */
10327error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +010010328 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010329 hlua_ctx_destroy(hlua);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010330 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010331 return 1;
10332}
10333
10334static int hlua_cli_io_handler_fct(struct appctx *appctx)
10335{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010336 struct hlua_cli_ctx *ctx = appctx->svcctx;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010337 struct hlua *hlua;
Willy Tarreau475e4632022-05-27 10:26:46 +020010338 struct stconn *sc;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010339 struct hlua_function *fcn;
10340
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010341 hlua = ctx->hlua;
Willy Tarreauc12b3212022-05-27 11:08:15 +020010342 sc = appctx_sc(appctx);
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010343 fcn = ctx->fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010344
10345 /* If the stream is disconnect or closed, ldo nothing. */
Willy Tarreau475e4632022-05-27 10:26:46 +020010346 if (unlikely(sc->state == SC_ST_DIS || sc->state == SC_ST_CLO))
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010347 return 1;
10348
10349 /* Execute the function. */
10350 switch (hlua_ctx_resume(hlua, 1)) {
10351
10352 /* finished. */
10353 case HLUA_E_OK:
10354 return 1;
10355
10356 /* yield. */
10357 case HLUA_E_AGAIN:
10358 /* We want write. */
10359 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreau475e4632022-05-27 10:26:46 +020010360 sc_need_room(sc);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010361 /* Set the timeout. */
10362 if (hlua->wake_time != TICK_ETERNITY)
10363 task_schedule(hlua->task, hlua->wake_time);
10364 return 0;
10365
10366 /* finished with error. */
10367 case HLUA_E_ERRMSG:
10368 /* Display log. */
10369 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
10370 fcn->name, lua_tostring(hlua->T, -1));
10371 lua_pop(hlua->T, 1);
10372 return 1;
10373
Thierry Fournierd5b073c2018-05-21 19:42:47 +020010374 case HLUA_E_ETMOUT:
10375 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
10376 fcn->name);
10377 return 1;
10378
10379 case HLUA_E_NOMEM:
10380 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
10381 fcn->name);
10382 return 1;
10383
10384 case HLUA_E_YIELD: /* unexpected */
10385 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
10386 fcn->name);
10387 return 1;
10388
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010389 case HLUA_E_ERR:
10390 /* Display log. */
10391 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
10392 fcn->name);
10393 return 1;
10394
10395 default:
10396 return 1;
10397 }
10398
10399 return 1;
10400}
10401
10402static void hlua_cli_io_release_fct(struct appctx *appctx)
10403{
Willy Tarreaubcda5f62022-05-03 18:13:39 +020010404 struct hlua_cli_ctx *ctx = appctx->svcctx;
10405
10406 hlua_ctx_destroy(ctx->hlua);
10407 ctx->hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010408}
10409
10410/* This function is an LUA binding used for registering
10411 * new keywords in the cli. It expects a list of keywords
10412 * which are the "path". It is limited to 5 keywords. A
10413 * description of the command, a function to be executed
10414 * for the parsing and a function for io handlers.
10415 */
10416__LJMP static int hlua_register_cli(lua_State *L)
10417{
10418 struct cli_kw_list *cli_kws;
10419 const char *message;
10420 int ref_io;
10421 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010422 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010423 int index;
10424 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010425 struct buffer *trash;
10426 const char *kw[5];
10427 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010428 const char *errmsg;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010429
10430 MAY_LJMP(check_args(L, 3, "register_cli"));
10431
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010010432 if (hlua_gethlua(L)) {
10433 /* runtime processing */
10434 WILL_LJMP(luaL_error(L, "register_cli: not available outside of body context"));
10435 }
10436
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010437 /* First argument : an array of maximum 5 keywords. */
10438 if (!lua_istable(L, 1))
10439 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
10440
10441 /* Second argument : string with contextual message. */
10442 message = MAY_LJMP(luaL_checkstring(L, 2));
10443
10444 /* Third and fourth argument : lua function. */
10445 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
10446
Thierry Fournierf67442e2020-11-28 20:41:07 +010010447 /* Check for CLI service already registered */
10448 trash = get_trash_chunk();
10449 index = 0;
10450 lua_pushnil(L);
10451 memset(kw, 0, sizeof(kw));
10452 while (lua_next(L, 1) != 0) {
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010453 if (index >= CLI_PREFIX_KW_NB) {
10454 hlua_unref(L, ref_io);
Thierry Fournierf67442e2020-11-28 20:41:07 +010010455 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 +010010456 }
10457 if (lua_type(L, -1) != LUA_TSTRING) {
10458 hlua_unref(L, ref_io);
Thierry Fournierf67442e2020-11-28 20:41:07 +010010459 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010460 }
Thierry Fournierf67442e2020-11-28 20:41:07 +010010461 kw[index] = lua_tostring(L, -1);
10462 if (index == 0)
10463 chunk_printf(trash, "%s", kw[index]);
10464 else
10465 chunk_appendf(trash, " %s", kw[index]);
10466 index++;
10467 lua_pop(L, 1);
10468 }
10469 cli_kw = cli_find_kw_exact((char **)kw);
10470 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +010010471 fcn = cli_kw->private;
10472 if (fcn->function_ref[hlua_state_id] != -1) {
10473 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
10474 "This will become a hard error in version 2.5.\n", trash->area);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010475 hlua_unref(L, fcn->function_ref[hlua_state_id]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010010476 }
10477 fcn->function_ref[hlua_state_id] = ref_io;
10478 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +010010479 }
10480
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010481 /* Allocate and fill the sample fetch keyword struct. */
10482 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010483 if (!cli_kws) {
10484 errmsg = "Lua out of memory error.";
10485 goto error;
10486 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +010010487 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010488 if (!fcn) {
10489 errmsg = "Lua out of memory error.";
10490 goto error;
10491 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010492
10493 /* Fill path. */
10494 index = 0;
10495 lua_pushnil(L);
10496 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010497 if (index >= 5) {
10498 errmsg = "1st argument must be a table with a maximum of 5 entries";
10499 goto error;
10500 }
10501 if (lua_type(L, -1) != LUA_TSTRING) {
10502 errmsg = "1st argument must be a table filled with strings";
10503 goto error;
10504 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010505 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010506 if (!cli_kws->kw[0].str_kw[index]) {
10507 errmsg = "Lua out of memory error.";
10508 goto error;
10509 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010510 index++;
10511 lua_pop(L, 1);
10512 }
10513
10514 /* Copy help message. */
10515 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010516 if (!cli_kws->kw[0].usage) {
10517 errmsg = "Lua out of memory error.";
10518 goto error;
10519 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010520
10521 /* Fill fcn io handler. */
10522 len = strlen("<lua.cli>") + 1;
10523 for (i = 0; i < index; i++)
10524 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
10525 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010526 if (!fcn->name) {
10527 errmsg = "Lua out of memory error.";
10528 goto error;
10529 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010530 strncat((char *)fcn->name, "<lua.cli", len);
10531 for (i = 0; i < index; i++) {
10532 strncat((char *)fcn->name, ".", len);
10533 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
10534 }
10535 strncat((char *)fcn->name, ">", len);
Thierry Fournierc7492592020-11-28 23:57:24 +010010536 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010537
10538 /* Fill last entries. */
10539 cli_kws->kw[0].private = fcn;
10540 cli_kws->kw[0].parse = hlua_cli_parse_fct;
10541 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
10542 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
10543
10544 /* Register this new converter */
10545 cli_register_kw(cli_kws);
10546
10547 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010548
10549 error:
10550 release_hlua_function(fcn);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010010551 hlua_unref(L, ref_io);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +020010552 if (cli_kws) {
10553 for (i = 0; i < index; i++)
10554 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
10555 ha_free((char **)&(cli_kws->kw[0].usage));
10556 }
10557 ha_free(&cli_kws);
10558 WILL_LJMP(luaL_error(L, errmsg));
10559 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +010010560}
10561
Christopher Faulet69c581a2021-05-31 08:54:04 +020010562static int hlua_filter_init_per_thread(struct proxy *px, struct flt_conf *fconf)
10563{
10564 struct hlua_flt_config *conf = fconf->conf;
10565 lua_State *L;
10566 int error, pos, state_id, flt_ref;
10567
10568 state_id = reg_flt_to_stack_id(conf->reg);
10569 L = hlua_states[state_id];
10570 pos = lua_gettop(L);
10571
10572 /* The filter parsing function */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010573 hlua_pushref(L, conf->reg->fun_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010574
10575 /* Push the filter class on the stack and resolve all callbacks */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010576 hlua_pushref(L, conf->reg->flt_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010577
10578 /* Duplicate the filter class so each filter will have its own copy */
10579 lua_newtable(L);
10580 lua_pushnil(L);
10581
10582 while (lua_next(L, pos+2)) {
10583 lua_pushvalue(L, -2);
10584 lua_insert(L, -2);
10585 lua_settable(L, -4);
10586 }
Aurelien DARRAGON73d1a982023-03-20 17:42:08 +010010587 flt_ref = hlua_ref(L);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010588
10589 /* Remove the original lua filter class from the stack */
10590 lua_pop(L, 1);
10591
10592 /* Push the copy on the stack */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010593 hlua_pushref(L, flt_ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010594
10595 /* extra args are pushed in a table */
10596 lua_newtable(L);
10597 for (pos = 0; conf->args[pos]; pos++) {
10598 /* Check stack available size. */
10599 if (!lua_checkstack(L, 1)) {
10600 ha_alert("Lua filter '%s' : Lua error : full stack.", conf->reg->name);
10601 goto error;
10602 }
10603 lua_pushstring(L, conf->args[pos]);
10604 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
10605 }
10606
10607 error = lua_pcall(L, 2, LUA_MULTRET, 0);
10608 switch (error) {
10609 case LUA_OK:
10610 /* replace the filter ref */
10611 conf->ref[state_id] = flt_ref;
10612 break;
10613 case LUA_ERRRUN:
10614 ha_alert("Lua filter '%s' : runtime error : %s", conf->reg->name, lua_tostring(L, -1));
10615 goto error;
10616 case LUA_ERRMEM:
10617 ha_alert("Lua filter '%s' : out of memory error", conf->reg->name);
10618 goto error;
10619 case LUA_ERRERR:
10620 ha_alert("Lua filter '%s' : message handler error : %s", conf->reg->name, lua_tostring(L, -1));
10621 goto error;
10622#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
10623 case LUA_ERRGCMM:
10624 ha_alert("Lua filter '%s' : garbage collector error : %s", conf->reg->name, lua_tostring(L, -1));
10625 goto error;
10626#endif
10627 default:
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050010628 ha_alert("Lua filter '%s' : unknown error : %s", conf->reg->name, lua_tostring(L, -1));
Christopher Faulet69c581a2021-05-31 08:54:04 +020010629 goto error;
10630 }
10631
10632 lua_settop(L, 0);
10633 return 0;
10634
10635 error:
10636 lua_settop(L, 0);
10637 return -1;
10638}
10639
10640static void hlua_filter_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
10641{
10642 struct hlua_flt_config *conf = fconf->conf;
10643 lua_State *L;
10644 int state_id;
10645
10646 if (!conf)
10647 return;
10648
10649 state_id = reg_flt_to_stack_id(conf->reg);
10650 L = hlua_states[state_id];
Aurelien DARRAGONfde199d2023-03-20 15:09:33 +010010651 hlua_unref(L, conf->ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010652}
10653
10654static int hlua_filter_init(struct proxy *px, struct flt_conf *fconf)
10655{
10656 struct hlua_flt_config *conf = fconf->conf;
10657 int state_id = reg_flt_to_stack_id(conf->reg);
10658
10659 /* Rely on per-thread init for global scripts */
10660 if (!state_id)
10661 return hlua_filter_init_per_thread(px, fconf);
10662 return 0;
10663}
10664
10665static void hlua_filter_deinit(struct proxy *px, struct flt_conf *fconf)
10666{
10667
10668 if (fconf->conf) {
10669 struct hlua_flt_config *conf = fconf->conf;
10670 int state_id = reg_flt_to_stack_id(conf->reg);
10671 int pos;
10672
10673 /* Rely on per-thread deinit for global scripts */
10674 if (!state_id)
10675 hlua_filter_deinit_per_thread(px, fconf);
10676
10677 for (pos = 0; conf->args[pos]; pos++)
10678 free(conf->args[pos]);
10679 free(conf->args);
10680 }
10681 ha_free(&fconf->conf);
10682 ha_free((char **)&fconf->id);
10683 ha_free(&fconf->ops);
10684}
10685
10686static int hlua_filter_new(struct stream *s, struct filter *filter)
10687{
10688 struct hlua_flt_config *conf = FLT_CONF(filter);
10689 struct hlua_flt_ctx *flt_ctx = NULL;
10690 int ret = 1;
10691
10692 /* In the execution wrappers linked with a stream, the
10693 * Lua context can be not initialized. This behavior
10694 * permits to save performances because a systematic
10695 * Lua initialization cause 5% performances loss.
10696 */
10697 if (!s->hlua) {
10698 struct hlua *hlua;
10699
10700 hlua = pool_alloc(pool_head_hlua);
10701 if (!hlua) {
10702 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
10703 conf->reg->name);
10704 ret = 0;
10705 goto end;
10706 }
10707 HLUA_INIT(hlua);
10708 s->hlua = hlua;
10709 if (!hlua_ctx_init(s->hlua, reg_flt_to_stack_id(conf->reg), s->task, 0)) {
10710 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
10711 conf->reg->name);
10712 ret = 0;
10713 goto end;
10714 }
10715 }
10716
10717 flt_ctx = pool_zalloc(pool_head_hlua_flt_ctx);
10718 if (!flt_ctx) {
10719 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10720 conf->reg->name);
10721 ret = 0;
10722 goto end;
10723 }
10724 flt_ctx->hlua[0] = pool_alloc(pool_head_hlua);
10725 flt_ctx->hlua[1] = pool_alloc(pool_head_hlua);
10726 if (!flt_ctx->hlua[0] || !flt_ctx->hlua[1]) {
10727 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10728 conf->reg->name);
10729 ret = 0;
10730 goto end;
10731 }
10732 HLUA_INIT(flt_ctx->hlua[0]);
10733 HLUA_INIT(flt_ctx->hlua[1]);
10734 if (!hlua_ctx_init(flt_ctx->hlua[0], reg_flt_to_stack_id(conf->reg), s->task, 0) ||
10735 !hlua_ctx_init(flt_ctx->hlua[1], reg_flt_to_stack_id(conf->reg), s->task, 0)) {
10736 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
10737 conf->reg->name);
10738 ret = 0;
10739 goto end;
10740 }
10741
10742 if (!HLUA_IS_RUNNING(s->hlua)) {
10743 /* The following Lua calls can fail. */
10744 if (!SET_SAFE_LJMP(s->hlua)) {
10745 const char *error;
10746
10747 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
10748 error = lua_tostring(s->hlua->T, -1);
10749 else
10750 error = "critical error";
10751 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
10752 ret = 0;
10753 goto end;
10754 }
10755
10756 /* Check stack size. */
10757 if (!lua_checkstack(s->hlua->T, 1)) {
10758 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
Tim Duesterhus22817382021-09-11 23:17:25 +020010759 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010760 ret = 0;
10761 goto end;
10762 }
10763
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010764 hlua_pushref(s->hlua->T, conf->ref[s->hlua->state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010765 if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) {
10766 SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
10767 conf->reg->name);
10768 RESET_SAFE_LJMP(s->hlua);
10769 ret = 0;
10770 goto end;
10771 }
10772 lua_insert(s->hlua->T, -2);
10773
10774 /* Push the copy on the stack */
10775 s->hlua->nargs = 1;
10776
10777 /* We must initialize the execution timeouts. */
10778 s->hlua->max_time = hlua_timeout_session;
10779
10780 /* At this point the execution is safe. */
10781 RESET_SAFE_LJMP(s->hlua);
10782 }
10783
10784 switch (hlua_ctx_resume(s->hlua, 0)) {
10785 case HLUA_E_OK:
10786 /* Nothing returned or not a table, ignore the filter for current stream */
10787 if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) {
10788 ret = 0;
10789 goto end;
10790 }
10791
10792 /* Attached the filter pointer to the ctx */
10793 lua_pushstring(s->hlua->T, "__filter");
10794 lua_pushlightuserdata(s->hlua->T, filter);
10795 lua_settable(s->hlua->T, -3);
10796
10797 /* Save a ref on the filter ctx */
10798 lua_pushvalue(s->hlua->T, 1);
Aurelien DARRAGON73d1a982023-03-20 17:42:08 +010010799 flt_ctx->ref = hlua_ref(s->hlua->T);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010800 filter->ctx = flt_ctx;
10801 break;
10802 case HLUA_E_ERRMSG:
10803 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(s->hlua->T, -1));
10804 ret = -1;
10805 goto end;
10806 case HLUA_E_ETMOUT:
10807 SEND_ERR(s->be, "Lua filter '%s' : 'new' execution timeout.\n", conf->reg->name);
10808 ret = 0;
10809 goto end;
10810 case HLUA_E_NOMEM:
10811 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
10812 ret = 0;
10813 goto end;
10814 case HLUA_E_AGAIN:
10815 case HLUA_E_YIELD:
10816 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
10817 " are not allowed from 'new' function.\n", conf->reg->name);
10818 ret = 0;
10819 goto end;
10820 case HLUA_E_ERR:
10821 SEND_ERR(s->be, "Lua filter '%s': 'new' returns an unknown error.\n", conf->reg->name);
10822 ret = 0;
10823 goto end;
10824 default:
10825 ret = 0;
10826 goto end;
10827 }
10828
10829 end:
10830 if (s->hlua)
10831 lua_settop(s->hlua->T, 0);
10832 if (ret <= 0) {
10833 if (flt_ctx) {
10834 hlua_ctx_destroy(flt_ctx->hlua[0]);
10835 hlua_ctx_destroy(flt_ctx->hlua[1]);
10836 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
10837 }
10838 }
10839 return ret;
10840}
10841
10842static void hlua_filter_delete(struct stream *s, struct filter *filter)
10843{
10844 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10845
Aurelien DARRAGONfde199d2023-03-20 15:09:33 +010010846 hlua_unref(s->hlua->T, flt_ctx->ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020010847 hlua_ctx_destroy(flt_ctx->hlua[0]);
10848 hlua_ctx_destroy(flt_ctx->hlua[1]);
10849 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
10850 filter->ctx = NULL;
10851}
10852
Christopher Faulet9f55a502020-02-25 15:21:02 +010010853static int hlua_filter_from_payload(struct filter *filter)
10854{
10855 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10856
10857 return (flt_ctx && !!(flt_ctx->flags & HLUA_FLT_CTX_FL_PAYLOAD));
10858}
10859
Christopher Fauletc404f112020-02-26 15:03:09 +010010860static int hlua_filter_callback(struct stream *s, struct filter *filter, const char *fun,
10861 int dir, unsigned int flags)
10862{
10863 struct hlua *flt_hlua;
10864 struct hlua_flt_config *conf = FLT_CONF(filter);
10865 struct hlua_flt_ctx *flt_ctx = filter->ctx;
10866 unsigned int hflags = HLUA_TXN_FLT_CTX;
10867 int ret = 1;
10868
10869 flt_hlua = flt_ctx->hlua[(dir == SMP_OPT_DIR_REQ ? 0 : 1)];
10870 if (!flt_hlua)
10871 goto end;
10872
10873 if (!HLUA_IS_RUNNING(flt_hlua)) {
10874 int extra_idx = lua_gettop(flt_hlua->T);
10875
10876 /* The following Lua calls can fail. */
10877 if (!SET_SAFE_LJMP(flt_hlua)) {
10878 const char *error;
10879
10880 if (lua_type(flt_hlua->T, -1) == LUA_TSTRING)
10881 error = lua_tostring(flt_hlua->T, -1);
10882 else
10883 error = "critical error";
10884 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
10885 goto end;
10886 }
10887
10888 /* Check stack size. */
10889 if (!lua_checkstack(flt_hlua->T, 3)) {
10890 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10891 RESET_SAFE_LJMP(flt_hlua);
10892 goto end;
10893 }
10894
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010010895 hlua_pushref(flt_hlua->T, flt_ctx->ref);
Christopher Fauletc404f112020-02-26 15:03:09 +010010896 if (lua_getfield(flt_hlua->T, -1, fun) != LUA_TFUNCTION) {
10897 RESET_SAFE_LJMP(flt_hlua);
10898 goto end;
10899 }
10900 lua_insert(flt_hlua->T, -2);
10901
10902 if (!hlua_txn_new(flt_hlua->T, s, s->be, dir, hflags)) {
10903 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10904 RESET_SAFE_LJMP(flt_hlua);
10905 goto end;
10906 }
10907 flt_hlua->nargs = 2;
10908
10909 if (flags & HLUA_FLT_CB_ARG_CHN) {
10910 if (dir == SMP_OPT_DIR_REQ)
10911 lua_getfield(flt_hlua->T, -1, "req");
10912 else
10913 lua_getfield(flt_hlua->T, -1, "res");
10914 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
10915 lua_pushstring(flt_hlua->T, "__filter");
10916 lua_pushlightuserdata(flt_hlua->T, filter);
10917 lua_settable(flt_hlua->T, -3);
10918 }
10919 flt_hlua->nargs++;
10920 }
10921 else if (flags & HLUA_FLT_CB_ARG_HTTP_MSG) {
Christopher Fauleteae8afa2020-02-26 17:15:48 +010010922 if (dir == SMP_OPT_DIR_REQ)
10923 lua_getfield(flt_hlua->T, -1, "http_req");
10924 else
10925 lua_getfield(flt_hlua->T, -1, "http_res");
10926 if (lua_type(flt_hlua->T, -1) == LUA_TTABLE) {
10927 lua_pushstring(flt_hlua->T, "__filter");
10928 lua_pushlightuserdata(flt_hlua->T, filter);
10929 lua_settable(flt_hlua->T, -3);
10930 }
10931 flt_hlua->nargs++;
Christopher Fauletc404f112020-02-26 15:03:09 +010010932 }
10933
10934 /* Check stack size. */
10935 if (!lua_checkstack(flt_hlua->T, 1)) {
10936 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
10937 RESET_SAFE_LJMP(flt_hlua);
10938 goto end;
10939 }
10940
10941 while (extra_idx--) {
10942 lua_pushvalue(flt_hlua->T, 1);
10943 lua_remove(flt_hlua->T, 1);
10944 flt_hlua->nargs++;
10945 }
10946
10947 /* We must initialize the execution timeouts. */
10948 flt_hlua->max_time = hlua_timeout_session;
10949
10950 /* At this point the execution is safe. */
10951 RESET_SAFE_LJMP(flt_hlua);
10952 }
10953
10954 switch (hlua_ctx_resume(flt_hlua, !(flags & HLUA_FLT_CB_FINAL))) {
10955 case HLUA_E_OK:
10956 /* Catch the return value if it required */
10957 if ((flags & HLUA_FLT_CB_RETVAL) && lua_gettop(flt_hlua->T) > 0) {
10958 ret = lua_tointeger(flt_hlua->T, -1);
10959 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
10960 }
10961
10962 /* Set timeout in the required channel. */
10963 if (flt_hlua->wake_time != TICK_ETERNITY) {
10964 if (dir == SMP_OPT_DIR_REQ)
10965 s->req.analyse_exp = flt_hlua->wake_time;
10966 else
10967 s->res.analyse_exp = flt_hlua->wake_time;
10968 }
10969 break;
10970 case HLUA_E_AGAIN:
10971 /* Set timeout in the required channel. */
10972 if (flt_hlua->wake_time != TICK_ETERNITY) {
10973 if (dir == SMP_OPT_DIR_REQ)
10974 s->req.analyse_exp = flt_hlua->wake_time;
10975 else
10976 s->res.analyse_exp = flt_hlua->wake_time;
10977 }
10978 /* Some actions can be wake up when a "write" event
10979 * is detected on a response channel. This is useful
10980 * only for actions targeted on the requests.
10981 */
10982 if (HLUA_IS_WAKERESWR(flt_hlua))
10983 s->res.flags |= CF_WAKE_WRITE;
10984 if (HLUA_IS_WAKEREQWR(flt_hlua))
10985 s->req.flags |= CF_WAKE_WRITE;
10986 ret = 0;
10987 goto end;
10988 case HLUA_E_ERRMSG:
10989 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(flt_hlua->T, -1));
10990 ret = -1;
10991 goto end;
10992 case HLUA_E_ETMOUT:
10993 SEND_ERR(s->be, "Lua filter '%s' : '%s' callback execution timeout.\n", conf->reg->name, fun);
10994 goto end;
10995 case HLUA_E_NOMEM:
10996 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
10997 goto end;
10998 case HLUA_E_YIELD:
10999 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
11000 " are not allowed from '%s' callback.\n", conf->reg->name, fun);
11001 goto end;
11002 case HLUA_E_ERR:
11003 SEND_ERR(s->be, "Lua filter '%s': '%s' returns an unknown error.\n", conf->reg->name, fun);
11004 goto end;
11005 default:
11006 goto end;
11007 }
11008
11009
11010 end:
11011 return ret;
11012}
11013
11014static int hlua_filter_start_analyze(struct stream *s, struct filter *filter, struct channel *chn)
11015{
11016 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11017
11018 flt_ctx->flags = 0;
11019 return hlua_filter_callback(s, filter, "start_analyze",
11020 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11021 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
11022}
11023
11024static int hlua_filter_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
11025{
11026 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11027
11028 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11029 return hlua_filter_callback(s, filter, "end_analyze",
11030 (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11031 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_CHN));
11032}
11033
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011034static int hlua_filter_http_headers(struct stream *s, struct filter *filter, struct http_msg *msg)
11035{
11036 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11037
11038 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11039 return hlua_filter_callback(s, filter, "http_headers",
11040 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11041 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
11042}
11043
11044static int hlua_filter_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
11045 unsigned int offset, unsigned int len)
11046{
11047 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11048 struct hlua *flt_hlua;
11049 int dir = (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
11050 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
11051 int ret;
11052
11053 flt_hlua = flt_ctx->hlua[idx];
11054 flt_ctx->cur_off[idx] = offset;
11055 flt_ctx->cur_len[idx] = len;
11056 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
11057 ret = hlua_filter_callback(s, filter, "http_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_HTTP_MSG));
11058 if (ret != -1) {
11059 ret = flt_ctx->cur_len[idx];
11060 if (lua_gettop(flt_hlua->T) > 0) {
11061 ret = lua_tointeger(flt_hlua->T, -1);
11062 if (ret > flt_ctx->cur_len[idx])
11063 ret = flt_ctx->cur_len[idx];
11064 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11065 }
11066 }
11067 return ret;
11068}
11069
11070static int hlua_filter_http_end(struct stream *s, struct filter *filter, struct http_msg *msg)
11071{
11072 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11073
11074 flt_ctx->flags &= ~HLUA_FLT_CTX_FL_PAYLOAD;
11075 return hlua_filter_callback(s, filter, "http_end",
11076 (!(msg->chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES),
11077 (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_RETVAL | HLUA_FLT_CB_ARG_HTTP_MSG));
11078}
11079
Christopher Fauletc404f112020-02-26 15:03:09 +010011080static int hlua_filter_tcp_payload(struct stream *s, struct filter *filter, struct channel *chn,
11081 unsigned int offset, unsigned int len)
11082{
11083 struct hlua_flt_ctx *flt_ctx = filter->ctx;
11084 struct hlua *flt_hlua;
11085 int dir = (!(chn->flags & CF_ISRESP) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
11086 int idx = (dir == SMP_OPT_DIR_REQ ? 0 : 1);
11087 int ret;
11088
11089 flt_hlua = flt_ctx->hlua[idx];
11090 flt_ctx->cur_off[idx] = offset;
11091 flt_ctx->cur_len[idx] = len;
11092 flt_ctx->flags |= HLUA_FLT_CTX_FL_PAYLOAD;
11093 ret = hlua_filter_callback(s, filter, "tcp_payload", dir, (HLUA_FLT_CB_FINAL | HLUA_FLT_CB_ARG_CHN));
11094 if (ret != -1) {
11095 ret = flt_ctx->cur_len[idx];
11096 if (lua_gettop(flt_hlua->T) > 0) {
11097 ret = lua_tointeger(flt_hlua->T, -1);
11098 if (ret > flt_ctx->cur_len[idx])
11099 ret = flt_ctx->cur_len[idx];
11100 lua_settop(flt_hlua->T, 0); /* Empty the stack. */
11101 }
11102 }
11103 return ret;
11104}
11105
Christopher Faulet69c581a2021-05-31 08:54:04 +020011106static int hlua_filter_parse_fct(char **args, int *cur_arg, struct proxy *px,
11107 struct flt_conf *fconf, char **err, void *private)
11108{
11109 struct hlua_reg_filter *reg_flt = private;
11110 lua_State *L;
11111 struct hlua_flt_config *conf = NULL;
11112 const char *flt_id = NULL;
11113 int state_id, pos, flt_flags = 0;
11114 struct flt_ops *hlua_flt_ops = NULL;
11115
11116 state_id = reg_flt_to_stack_id(reg_flt);
11117 L = hlua_states[state_id];
11118
11119 /* Initialize the filter ops with default callbacks */
11120 hlua_flt_ops = calloc(1, sizeof(*hlua_flt_ops));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011121 if (!hlua_flt_ops)
11122 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011123 hlua_flt_ops->init = hlua_filter_init;
11124 hlua_flt_ops->deinit = hlua_filter_deinit;
11125 if (state_id) {
11126 /* Set per-thread callback if script is loaded per-thread */
11127 hlua_flt_ops->init_per_thread = hlua_filter_init_per_thread;
11128 hlua_flt_ops->deinit_per_thread = hlua_filter_deinit_per_thread;
11129 }
11130 hlua_flt_ops->attach = hlua_filter_new;
11131 hlua_flt_ops->detach = hlua_filter_delete;
11132
11133 /* Push the filter class on the stack and resolve all callbacks */
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011134 hlua_pushref(L, reg_flt->flt_ref[state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011135
Christopher Fauletc404f112020-02-26 15:03:09 +010011136 if (lua_getfield(L, -1, "start_analyze") == LUA_TFUNCTION)
11137 hlua_flt_ops->channel_start_analyze = hlua_filter_start_analyze;
11138 lua_pop(L, 1);
11139 if (lua_getfield(L, -1, "end_analyze") == LUA_TFUNCTION)
11140 hlua_flt_ops->channel_end_analyze = hlua_filter_end_analyze;
11141 lua_pop(L, 1);
Christopher Fauleteae8afa2020-02-26 17:15:48 +010011142 if (lua_getfield(L, -1, "http_headers") == LUA_TFUNCTION)
11143 hlua_flt_ops->http_headers = hlua_filter_http_headers;
11144 lua_pop(L, 1);
11145 if (lua_getfield(L, -1, "http_payload") == LUA_TFUNCTION)
11146 hlua_flt_ops->http_payload = hlua_filter_http_payload;
11147 lua_pop(L, 1);
11148 if (lua_getfield(L, -1, "http_end") == LUA_TFUNCTION)
11149 hlua_flt_ops->http_end = hlua_filter_http_end;
11150 lua_pop(L, 1);
Christopher Fauletc404f112020-02-26 15:03:09 +010011151 if (lua_getfield(L, -1, "tcp_payload") == LUA_TFUNCTION)
11152 hlua_flt_ops->tcp_payload = hlua_filter_tcp_payload;
11153 lua_pop(L, 1);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011154
11155 /* Get id and flags of the filter class */
11156 if (lua_getfield(L, -1, "id") == LUA_TSTRING)
11157 flt_id = lua_tostring(L, -1);
11158 lua_pop(L, 1);
11159 if (lua_getfield(L, -1, "flags") == LUA_TNUMBER)
11160 flt_flags = lua_tointeger(L, -1);
11161 lua_pop(L, 1);
11162
11163 /* Create the filter config */
11164 conf = calloc(1, sizeof(*conf));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011165 if (!conf)
Christopher Faulet69c581a2021-05-31 08:54:04 +020011166 goto error;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011167 conf->reg = reg_flt;
11168
11169 /* duplicate args */
11170 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++);
11171 conf->args = calloc(pos + 1, sizeof(*conf->args));
Christopher Fauletc86bb872021-08-13 08:33:57 +020011172 if (!conf->args)
11173 goto error;
11174 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++) {
Christopher Faulet69c581a2021-05-31 08:54:04 +020011175 conf->args[pos] = strdup(args[*cur_arg + 1 + pos]);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011176 if (!conf->args[pos])
11177 goto error;
11178 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011179 conf->args[pos] = NULL;
11180 *cur_arg += pos + 1;
11181
Christopher Fauletc86bb872021-08-13 08:33:57 +020011182 if (flt_id) {
11183 fconf->id = strdup(flt_id);
11184 if (!fconf->id)
11185 goto error;
11186 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011187 fconf->flags = flt_flags;
11188 fconf->conf = conf;
11189 fconf->ops = hlua_flt_ops;
11190
11191 lua_settop(L, 0);
11192 return 0;
11193
11194 error:
Christopher Fauletc86bb872021-08-13 08:33:57 +020011195 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011196 free(hlua_flt_ops);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011197 if (conf && conf->args) {
11198 for (pos = 0; conf->args[pos]; pos++)
11199 free(conf->args[pos]);
11200 free(conf->args);
11201 }
Christopher Faulet69c581a2021-05-31 08:54:04 +020011202 free(conf);
Christopher Fauletc86bb872021-08-13 08:33:57 +020011203 free((char *)fconf->id);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011204 lua_settop(L, 0);
11205 return -1;
11206}
11207
Christopher Fauletc404f112020-02-26 15:03:09 +010011208__LJMP static int hlua_register_data_filter(lua_State *L)
11209{
11210 struct filter *filter;
11211 struct channel *chn;
11212
11213 MAY_LJMP(check_args(L, 2, "register_data_filter"));
11214 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
11215 chn = MAY_LJMP(hlua_checkchannel(L, 2));
11216
11217 lua_getfield(L, 1, "__filter");
11218 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
11219 filter = lua_touserdata (L, -1);
11220 lua_pop(L, 1);
11221
11222 register_data_filter(chn_strm(chn), chn, filter);
11223 return 1;
11224}
11225
11226__LJMP static int hlua_unregister_data_filter(lua_State *L)
11227{
11228 struct filter *filter;
11229 struct channel *chn;
11230
11231 MAY_LJMP(check_args(L, 2, "unregister_data_filter"));
11232 MAY_LJMP(luaL_checktype(L, 1, LUA_TTABLE));
11233 chn = MAY_LJMP(hlua_checkchannel(L, 2));
11234
11235 lua_getfield(L, 1, "__filter");
11236 MAY_LJMP(luaL_checktype(L, -1, LUA_TLIGHTUSERDATA));
11237 filter = lua_touserdata (L, -1);
11238 lua_pop(L, 1);
11239
11240 unregister_data_filter(chn_strm(chn), chn, filter);
11241 return 1;
11242}
11243
Christopher Faulet69c581a2021-05-31 08:54:04 +020011244/* This function is an LUA binding used for registering a filter. It expects a
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050011245 * filter name used in the haproxy configuration file and a LUA function to
Christopher Faulet69c581a2021-05-31 08:54:04 +020011246 * parse configuration arguments.
11247 */
11248__LJMP static int hlua_register_filter(lua_State *L)
11249{
11250 struct buffer *trash;
11251 struct flt_kw_list *fkl;
11252 struct flt_kw *fkw;
11253 const char *name;
11254 struct hlua_reg_filter *reg_flt= NULL;
11255 int flt_ref, fun_ref;
11256 int len;
11257
11258 MAY_LJMP(check_args(L, 3, "register_filter"));
11259
Aurelien DARRAGON87f52972023-02-24 09:43:54 +010011260 if (hlua_gethlua(L)) {
11261 /* runtime processing */
11262 WILL_LJMP(luaL_error(L, "register_filter: not available outside of body context"));
11263 }
11264
Christopher Faulet69c581a2021-05-31 08:54:04 +020011265 /* First argument : filter name. */
11266 name = MAY_LJMP(luaL_checkstring(L, 1));
11267
11268 /* Second argument : The filter class */
11269 flt_ref = MAY_LJMP(hlua_checktable(L, 2));
11270
11271 /* Third argument : lua function. */
11272 fun_ref = MAY_LJMP(hlua_checkfunction(L, 3));
11273
11274 trash = get_trash_chunk();
11275 chunk_printf(trash, "lua.%s", name);
11276 fkw = flt_find_kw(trash->area);
11277 if (fkw != NULL) {
11278 reg_flt = fkw->private;
11279 if (reg_flt->flt_ref[hlua_state_id] != -1 || reg_flt->fun_ref[hlua_state_id] != -1) {
11280 ha_warning("Trying to register filter 'lua.%s' more than once. "
11281 "This will become a hard error in version 2.5.\n", name);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011282 if (reg_flt->flt_ref[hlua_state_id] != -1)
11283 hlua_unref(L, reg_flt->flt_ref[hlua_state_id]);
11284 if (reg_flt->fun_ref[hlua_state_id] != -1)
11285 hlua_unref(L, reg_flt->fun_ref[hlua_state_id]);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011286 }
11287 reg_flt->flt_ref[hlua_state_id] = flt_ref;
11288 reg_flt->fun_ref[hlua_state_id] = fun_ref;
11289 return 0;
11290 }
11291
11292 fkl = calloc(1, sizeof(*fkl) + sizeof(struct flt_kw) * 2);
11293 if (!fkl)
11294 goto alloc_error;
11295 fkl->scope = "HLUA";
11296
11297 reg_flt = new_hlua_reg_filter(name);
11298 if (!reg_flt)
11299 goto alloc_error;
11300
11301 reg_flt->flt_ref[hlua_state_id] = flt_ref;
11302 reg_flt->fun_ref[hlua_state_id] = fun_ref;
11303
11304 /* The filter keyword */
11305 len = strlen("lua.") + strlen(name) + 1;
11306 fkl->kw[0].kw = calloc(1, len);
11307 if (!fkl->kw[0].kw)
11308 goto alloc_error;
11309
11310 snprintf((char *)fkl->kw[0].kw, len, "lua.%s", name);
11311
11312 fkl->kw[0].parse = hlua_filter_parse_fct;
11313 fkl->kw[0].private = reg_flt;
11314 memset(&fkl->kw[1], 0, sizeof(*fkl->kw));
11315
11316 /* Register this new filter */
11317 flt_register_keywords(fkl);
11318
11319 return 0;
11320
11321 alloc_error:
11322 release_hlua_reg_filter(reg_flt);
Aurelien DARRAGON55afbed2023-03-02 18:42:06 +010011323 hlua_unref(L, flt_ref);
11324 hlua_unref(L, fun_ref);
Christopher Faulet69c581a2021-05-31 08:54:04 +020011325 ha_free(&fkl);
11326 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
11327 return 0; /* Never reached */
11328}
11329
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011330static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011331 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011332 char **err, unsigned int *timeout)
11333{
11334 const char *error;
11335
11336 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +020011337 if (error == PARSE_TIME_OVER) {
11338 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
11339 args[1], args[0]);
11340 return -1;
11341 }
11342 else if (error == PARSE_TIME_UNDER) {
11343 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
11344 args[1], args[0]);
11345 return -1;
11346 }
11347 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011348 memprintf(err, "%s: invalid timeout", args[0]);
11349 return -1;
11350 }
11351 return 0;
11352}
11353
11354static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011355 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011356 char **err)
11357{
11358 return hlua_read_timeout(args, section_type, curpx, defpx,
11359 file, line, err, &hlua_timeout_session);
11360}
11361
11362static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011363 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011364 char **err)
11365{
11366 return hlua_read_timeout(args, section_type, curpx, defpx,
11367 file, line, err, &hlua_timeout_task);
11368}
11369
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011370static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011371 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020011372 char **err)
11373{
11374 return hlua_read_timeout(args, section_type, curpx, defpx,
11375 file, line, err, &hlua_timeout_applet);
11376}
11377
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011378static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011379 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011380 char **err)
11381{
11382 char *error;
11383
11384 hlua_nb_instruction = strtoll(args[1], &error, 10);
11385 if (*error != '\0') {
11386 memprintf(err, "%s: invalid number", args[0]);
11387 return -1;
11388 }
11389 return 0;
11390}
11391
Willy Tarreau32f61e22015-03-18 17:54:59 +010011392static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011393 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +010011394 char **err)
11395{
11396 char *error;
11397
11398 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011399 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).", args[0]);
Willy Tarreau32f61e22015-03-18 17:54:59 +010011400 return -1;
11401 }
11402 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
11403 if (*error != '\0') {
11404 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
11405 return -1;
11406 }
11407 return 0;
11408}
11409
11410
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011411/* This function is called by the main configuration key "lua-load". It loads and
11412 * execute an lua file during the parsing of the HAProxy configuration file. It is
11413 * the main lua entry point.
11414 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080011415 * This function runs with the HAProxy keywords API. It returns -1 if an error
11416 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011417 *
11418 * In some error case, LUA set an error message in top of the stack. This function
11419 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020011420 *
11421 * This function can fail with an abort() due to an Lua critical error.
11422 * We are in the configuration parsing process of HAProxy, this abort() is
11423 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011424 */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011425static int hlua_load_state(char **args, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011426{
11427 int error;
Thierry Fournierae6b5682022-09-19 09:04:16 +020011428 int nargs;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011429
11430 /* Just load and compile the file. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011431 error = luaL_loadfile(L, args[0]);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011432 if (error) {
Thierry Fournierae6b5682022-09-19 09:04:16 +020011433 memprintf(err, "error in Lua file '%s': %s", args[0], lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011434 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011435 return -1;
11436 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011437
11438 /* Push args in the Lua stack, except the first one which is the filename */
11439 for (nargs = 1; *(args[nargs]) != 0; nargs++) {
Aurelien DARRAGON4d7aefe2022-09-23 10:22:14 +020011440 /* Check stack size. */
11441 if (!lua_checkstack(L, 1)) {
11442 memprintf(err, "Lua runtime error while loading arguments: stack is full.");
11443 return -1;
11444 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011445 lua_pushstring(L, args[nargs]);
11446 }
11447 nargs--;
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011448
11449 /* If no syntax error where detected, execute the code. */
Thierry Fournierae6b5682022-09-19 09:04:16 +020011450 error = lua_pcall(L, nargs, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011451 switch (error) {
11452 case LUA_OK:
11453 break;
11454 case LUA_ERRRUN:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011455 memprintf(err, "Lua runtime error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011456 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011457 return -1;
11458 case LUA_ERRMEM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011459 memprintf(err, "Lua out of memory error");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011460 return -1;
11461 case LUA_ERRERR:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011462 memprintf(err, "Lua message handler error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011463 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011464 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020011465#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011466 case LUA_ERRGCMM:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011467 memprintf(err, "Lua garbage collector error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011468 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011469 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +020011470#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011471 default:
Thierry Fournier70e38e92022-09-19 09:01:53 +020011472 memprintf(err, "Lua unknown error: %s", lua_tostring(L, -1));
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011473 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011474 return -1;
11475 }
11476
11477 return 0;
11478}
11479
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011480static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011481 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011482 char **err)
11483{
11484 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011485 memprintf(err, "'%s' expects a file name as parameter.", args[0]);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011486 return -1;
11487 }
11488
Thierry Fournier59f11be2020-11-29 00:37:41 +010011489 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +010011490 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011491 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020011492 return hlua_load_state(&args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +010011493}
11494
Thierry Fournier59f11be2020-11-29 00:37:41 +010011495static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011496 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +010011497 char **err)
11498{
11499 int len;
Thierry Fournierae6b5682022-09-19 09:04:16 +020011500 int i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011501
11502 if (*(args[1]) == 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011503 memprintf(err, "'%s' expects a file as parameter.", args[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011504 return -1;
11505 }
11506
11507 if (per_thread_load == NULL) {
11508 /* allocate the first entry large enough to store the final NULL */
11509 per_thread_load = calloc(1, sizeof(*per_thread_load));
11510 if (per_thread_load == NULL) {
11511 memprintf(err, "out of memory error");
11512 return -1;
11513 }
11514 }
11515
11516 /* count used entries */
11517 for (len = 0; per_thread_load[len] != NULL; len++)
11518 ;
11519
11520 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
11521 if (per_thread_load == NULL) {
11522 memprintf(err, "out of memory error");
11523 return -1;
11524 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010011525 per_thread_load[len + 1] = NULL;
11526
Thierry Fournierae6b5682022-09-19 09:04:16 +020011527 /* count args excepting the first, allocate array and copy args */
11528 for (i = 0; *(args[i + 1]) != 0; i++);
Aurelien DARRAGONb12d1692022-09-23 08:48:34 +020011529 per_thread_load[len] = calloc(i + 1, sizeof(*per_thread_load[len]));
Thierry Fournier59f11be2020-11-29 00:37:41 +010011530 if (per_thread_load[len] == NULL) {
11531 memprintf(err, "out of memory error");
11532 return -1;
11533 }
Thierry Fournierae6b5682022-09-19 09:04:16 +020011534 for (i = 1; *(args[i]) != 0; i++) {
11535 per_thread_load[len][i - 1] = strdup(args[i]);
11536 if (per_thread_load[len][i - 1] == NULL) {
11537 memprintf(err, "out of memory error");
11538 return -1;
11539 }
11540 }
11541 per_thread_load[len][i - 1] = strdup("");
11542 if (per_thread_load[len][i - 1] == NULL) {
11543 memprintf(err, "out of memory error");
11544 return -1;
11545 }
Thierry Fournier59f11be2020-11-29 00:37:41 +010011546
11547 /* loading for thread 1 only */
11548 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011549 ha_set_thread(NULL);
Thierry Fournierae6b5682022-09-19 09:04:16 +020011550 return hlua_load_state(per_thread_load[len], hlua_states[1], err);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011551}
11552
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011553/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
11554 * in the given <ctx>.
11555 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +010011556static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011557{
Thierry Fournier3fb9e512020-11-28 10:13:12 +010011558 lua_getglobal(L, "package"); /* push package variable */
11559 lua_pushstring(L, path); /* push given path */
11560 lua_pushstring(L, ";"); /* push semicolon */
11561 lua_getfield(L, -3, type); /* push old path */
11562 lua_concat(L, 3); /* concatenate to new path */
11563 lua_setfield(L, -2, type); /* store new path */
11564 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +010011565
11566 return 0;
11567}
11568
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011569static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +010011570 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011571 char **err)
11572{
11573 char *path;
11574 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011575 struct prepend_path *p = NULL;
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000011576 size_t i;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011577
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011578 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011579 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011580 }
11581
11582 if (!(*args[1])) {
11583 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011584 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011585 }
11586 path = args[1];
11587
11588 if (*args[2]) {
11589 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
11590 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011591 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011592 }
11593 type = args[2];
11594 }
11595
Thierry Fournier59f11be2020-11-29 00:37:41 +010011596 p = calloc(1, sizeof(*p));
11597 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011598 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011599 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011600 }
11601 p->path = strdup(path);
11602 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011603 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011604 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011605 }
11606 p->type = strdup(type);
11607 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +010011608 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011609 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011610 }
Willy Tarreau2b718102021-04-21 07:32:39 +020011611 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011612
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020011613 /* Handle the global state and the per-thread state for the first
11614 * thread. The remaining threads will be initialized based on
11615 * prepend_path_list.
11616 */
Bertrand Jacquin7fbc7702021-11-24 21:16:06 +000011617 for (i = 0; i < 2; i++) {
Tim Duesterhus9e5e5862021-10-11 18:51:08 +020011618 lua_State *L = hlua_states[i];
11619 const char *error;
11620
11621 if (setjmp(safe_ljmp_env) != 0) {
11622 lua_atpanic(L, hlua_panic_safe);
11623 if (lua_type(L, -1) == LUA_TSTRING)
11624 error = lua_tostring(L, -1);
11625 else
11626 error = "critical error";
11627 fprintf(stderr, "lua-prepend-path: %s.\n", error);
11628 exit(1);
11629 } else {
11630 lua_atpanic(L, hlua_panic_ljmp);
11631 }
11632
11633 hlua_prepend_path(L, type, path);
11634
11635 lua_atpanic(L, hlua_panic_safe);
11636 }
11637
Thierry Fournier59f11be2020-11-29 00:37:41 +010011638 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +010011639
11640err2:
11641 free(p->type);
11642 free(p->path);
11643err:
11644 free(p);
11645 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011646}
11647
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011648/* configuration keywords declaration */
11649static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +010011650 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011651 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +010011652 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +010011653 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
11654 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +020011655 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +010011656 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +010011657 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +010011658 { 0, NULL, NULL },
11659}};
11660
Willy Tarreau0108d902018-11-25 19:14:37 +010011661INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
11662
William Lallemand52139182022-03-30 15:05:42 +020011663#ifdef USE_OPENSSL
Christopher Fauletafd8f102018-11-08 11:34:21 +010011664
William Lallemand30fcca12022-03-30 12:03:12 +020011665/*
11666 * This function replace a ckch_store by another one, and rebuild the ckch_inst and all its dependencies.
11667 * It does the sam as "cli_io_handler_commit_cert" but for lua, the major
11668 * difference is that the yield in lua and for the CLI is not handled the same
11669 * way.
11670 */
11671__LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext ctx)
11672{
11673 struct ckch_inst **lua_ckchi = lua_touserdata(L, -1);
11674 struct ckch_store **lua_ckchs = lua_touserdata(L, -2);
11675 struct ckch_inst *ckchi = *lua_ckchi;
11676 struct ckch_store *old_ckchs = lua_ckchs[0];
11677 struct ckch_store *new_ckchs = lua_ckchs[1];
11678 struct hlua *hlua;
11679 char *err = NULL;
11680 int y = 1;
11681
11682 hlua = hlua_gethlua(L);
11683
11684 /* get the first ckchi to copy */
11685 if (ckchi == NULL)
11686 ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
11687
11688 /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
11689 list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
11690 struct ckch_inst *new_inst;
11691
11692 /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
11693 if (y % 10 == 0) {
11694
11695 *lua_ckchi = ckchi;
11696
11697 task_wakeup(hlua->task, TASK_WOKEN_MSG);
11698 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
11699 }
11700
11701 if (ckch_inst_rebuild(new_ckchs, ckchi, &new_inst, &err))
11702 goto error;
11703
11704 /* link the new ckch_inst to the duplicate */
11705 LIST_APPEND(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
11706 y++;
11707 }
11708
11709 /* The generation is finished, we can insert everything */
11710 ckch_store_replace(old_ckchs, new_ckchs);
11711
11712 lua_pop(L, 2); /* pop the lua_ckchs and ckchi */
11713
11714 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11715
11716 return 0;
11717
11718error:
11719 ckch_store_free(new_ckchs);
11720 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11721 WILL_LJMP(luaL_error(L, "%s", err));
11722 free(err);
11723
11724 return 0;
11725}
11726
11727/*
11728 * Replace a ckch_store <filename> in the ckchs_tree with a ckch_store created
11729 * from the table in parameter.
11730 *
11731 * This is equivalent to "set ssl cert" + "commit ssl cert" over the CLI, which
11732 * means it does not need to have a transaction since everything is done in the
11733 * same function.
11734 *
11735 * CertCache.set{filename="", crt="", key="", sctl="", ocsp="", issuer=""}
11736 *
11737 */
11738__LJMP static int hlua_ckch_set(lua_State *L)
11739{
11740 struct hlua *hlua;
11741 struct ckch_inst **lua_ckchi;
11742 struct ckch_store **lua_ckchs;
11743 struct ckch_store *old_ckchs = NULL;
11744 struct ckch_store *new_ckchs = NULL;
11745 int errcode = 0;
11746 char *err = NULL;
11747 struct cert_exts *cert_ext = NULL;
11748 char *filename;
William Lallemand52ddd992022-11-22 11:51:53 +010011749 struct ckch_data *data;
William Lallemand30fcca12022-03-30 12:03:12 +020011750 int ret;
11751
11752 if (lua_type(L, -1) != LUA_TTABLE)
11753 WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
11754
11755 hlua = hlua_gethlua(L);
11756
11757 /* FIXME: this should not return an error but should come back later */
11758 if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
11759 WILL_LJMP(luaL_error(L, "CertCache already under lock"));
11760
11761 ret = lua_getfield(L, -1, "filename");
11762 if (ret != LUA_TSTRING) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011763 memprintf(&err, "%sNo filename specified!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011764 errcode |= ERR_ALERT | ERR_FATAL;
11765 goto end;
11766 }
11767 filename = (char *)lua_tostring(L, -1);
11768
11769
11770 /* look for the filename in the tree */
11771 old_ckchs = ckchs_lookup(filename);
11772 if (!old_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011773 memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011774 errcode |= ERR_ALERT | ERR_FATAL;
11775 goto end;
11776 }
11777 /* TODO: handle extra_files_noext */
11778
11779 new_ckchs = ckchs_dup(old_ckchs);
11780 if (!new_ckchs) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011781 memprintf(&err, "%sCannot allocate memory!", err ? err : "");
William Lallemand30fcca12022-03-30 12:03:12 +020011782 errcode |= ERR_ALERT | ERR_FATAL;
11783 goto end;
11784 }
11785
William Lallemand52ddd992022-11-22 11:51:53 +010011786 data = new_ckchs->data;
William Lallemand30fcca12022-03-30 12:03:12 +020011787
11788 /* loop on the field in the table, which have the same name as the
11789 * possible extensions of files */
11790 lua_pushnil(L);
11791 while (lua_next(L, 1)) {
11792 int i;
11793 const char *field = lua_tostring(L, -2);
11794 char *payload = (char *)lua_tostring(L, -1);
11795
11796 if (!field || strcmp(field, "filename") == 0) {
11797 lua_pop(L, 1);
11798 continue;
11799 }
11800
11801 for (i = 0; field && cert_exts[i].ext != NULL; i++) {
11802 if (strcmp(field, cert_exts[i].ext) == 0) {
11803 cert_ext = &cert_exts[i];
11804 break;
11805 }
11806 }
11807
11808 /* this is the default type, the field is not supported */
11809 if (cert_ext == NULL) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011810 memprintf(&err, "%sUnsupported field '%s'", err ? err : "", field);
William Lallemand30fcca12022-03-30 12:03:12 +020011811 errcode |= ERR_ALERT | ERR_FATAL;
11812 goto end;
11813 }
11814
11815 /* appply the change on the duplicate */
William Lallemand52ddd992022-11-22 11:51:53 +010011816 if (cert_ext->load(filename, payload, data, &err) != 0) {
Thierry Fournier70e38e92022-09-19 09:01:53 +020011817 memprintf(&err, "%sCan't load the payload for '%s'", err ? err : "", cert_ext->ext);
William Lallemand30fcca12022-03-30 12:03:12 +020011818 errcode |= ERR_ALERT | ERR_FATAL;
11819 goto end;
11820 }
11821 lua_pop(L, 1);
11822 }
11823
11824 /* store the pointers on the lua stack */
11825 lua_ckchs = lua_newuserdata(L, sizeof(struct ckch_store *) * 2);
11826 lua_ckchs[0] = old_ckchs;
11827 lua_ckchs[1] = new_ckchs;
11828 lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
11829 *lua_ckchi = NULL;
11830
11831 task_wakeup(hlua->task, TASK_WOKEN_MSG);
11832 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
11833
11834end:
11835 HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
11836
11837 if (errcode & ERR_CODE) {
11838 ckch_store_free(new_ckchs);
11839 WILL_LJMP(luaL_error(L, "%s", err));
11840 }
11841 free(err);
11842
11843 return 0;
11844}
11845
William Lallemand52139182022-03-30 15:05:42 +020011846#else
11847
11848__LJMP static int hlua_ckch_set(lua_State *L)
11849{
11850 WILL_LJMP(luaL_error(L, "'CertCache.set' needs an HAProxy built with OpenSSL"));
11851
11852 return 0;
11853}
11854#endif /* ! USE_OPENSSL */
11855
11856
11857
Thierry FOURNIERbabae282015-09-17 11:36:37 +020011858/* This function can fail with an abort() due to an Lua critical error.
11859 * We are in the initialisation process of HAProxy, this abort() is
11860 * tolerated.
11861 */
Thierry Fournierb8cef172020-11-28 15:37:17 +010011862int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011863{
11864 struct hlua_init_function *init;
11865 const char *msg;
11866 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +010011867 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +010011868 const char *kind;
11869 const char *trace;
11870 int return_status = 1;
11871#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
11872 int nres;
11873#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011874
Willy Tarreaucdb53462020-12-02 12:12:00 +010011875 /* disable memory limit checks if limit is not set */
11876 if (!hlua_global_allocator.limit)
11877 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
11878
Ilya Shipitsin856aabc2020-04-16 23:51:34 +050011879 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +010011880 if (setjmp(safe_ljmp_env) != 0) {
11881 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +010011882 if (lua_type(L, -1) == LUA_TSTRING)
11883 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011884 else
11885 error = "critical error";
11886 fprintf(stderr, "Lua post-init: %s.\n", error);
11887 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010011888 } else {
11889 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +010011890 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +020011891
Thierry Fournierc7492592020-11-28 23:57:24 +010011892 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Aurelien DARRAGON4fdf8b52023-03-20 17:22:37 +010011893 hlua_pushref(L, init->function_ref);
Aurelien DARRAGON16d047b2023-03-20 16:29:55 +010011894 /* function ref should be released right away since it was pushed
11895 * on the stack and will not be used anymore
11896 */
11897 hlua_unref(L, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +010011898
11899#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +010011900 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +010011901#else
Thierry Fournierb8cef172020-11-28 15:37:17 +010011902 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +010011903#endif
11904 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011905 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +010011906
11907 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +010011908 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +010011909 break;
Thierry Fournier670db242020-11-28 10:49:59 +010011910
11911 case LUA_ERRERR:
11912 kind = "message handler error";
Willy Tarreau14de3952022-11-14 07:08:28 +010011913 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011914 case LUA_ERRRUN:
11915 if (!kind)
11916 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010011917 msg = lua_tostring(L, -1);
11918 lua_settop(L, 0); /* Empty the stack. */
11919 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +010011920 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010011921 if (msg)
11922 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
11923 else
11924 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
11925 return_status = 0;
11926 break;
11927
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011928 default:
Thierry Fournier670db242020-11-28 10:49:59 +010011929 /* Unknown error */
11930 kind = "Unknown error";
Willy Tarreau14de3952022-11-14 07:08:28 +010011931 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011932 case LUA_YIELD:
11933 /* yield is not configured at this step, this state doesn't happen */
11934 if (!kind)
11935 kind = "yield not allowed";
Willy Tarreau14de3952022-11-14 07:08:28 +010011936 __fallthrough;
Thierry Fournier670db242020-11-28 10:49:59 +010011937 case LUA_ERRMEM:
11938 if (!kind)
11939 kind = "out of memory error";
Thierry Fournierb8cef172020-11-28 15:37:17 +010011940 lua_settop(L, 0);
11941 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +010011942 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +010011943 ha_alert("Lua init: %s: %s\n", kind, trace);
11944 return_status = 0;
11945 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011946 }
Thierry Fournier670db242020-11-28 10:49:59 +010011947 if (!return_status)
11948 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011949 }
Thierry Fournier3c539322020-11-28 16:05:05 +010011950
11951 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +010011952 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010011953}
11954
Thierry Fournierb8cef172020-11-28 15:37:17 +010011955int hlua_post_init()
11956{
Thierry Fournier59f11be2020-11-29 00:37:41 +010011957 int ret;
11958 int i;
11959 int errors;
11960 char *err = NULL;
11961 struct hlua_function *fcn;
Christopher Faulet69c581a2021-05-31 08:54:04 +020011962 struct hlua_reg_filter *reg_flt;
Thierry Fournier59f11be2020-11-29 00:37:41 +010011963
Willy Tarreaub1310492021-08-30 09:35:18 +020011964#if defined(USE_OPENSSL)
Thierry Fournierb8cef172020-11-28 15:37:17 +010011965 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010011966 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +010011967 int saved_used_backed = global.ssl_used_backend;
11968 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010011969 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +010011970 global.ssl_used_backend = saved_used_backed;
11971 }
11972#endif
11973
Thierry Fournierc7492592020-11-28 23:57:24 +010011974 /* Perform post init of common thread */
11975 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011976 ha_set_thread(&ha_thread_info[0]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011977 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
11978 if (ret == 0)
11979 return 0;
11980
11981 /* init remaining lua states and load files */
11982 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
11983
11984 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020011985 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010011986
11987 /* Init lua state */
11988 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
11989
11990 /* Load lua files */
11991 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
11992 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
11993 if (ret != 0) {
11994 ha_alert("Lua init: %s\n", err);
11995 return 0;
11996 }
11997 }
11998 }
11999
12000 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012001 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012002
12003 /* Execute post init for all states */
12004 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
12005
12006 /* set thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012007 ha_set_thread(&ha_thread_info[hlua_state_id - 1]);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012008
12009 /* run post init */
12010 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
12011 if (ret == 0)
12012 return 0;
12013 }
12014
12015 /* Reset thread context */
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012016 ha_set_thread(NULL);
Thierry Fournier59f11be2020-11-29 00:37:41 +010012017
12018 /* control functions registering. Each function must have:
12019 * - only the function_ref[0] set positive and all other to -1
12020 * - only the function_ref[0] set to -1 and all other positive
12021 * This ensure a same reference is not used both in shared
12022 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050012023 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +010012024 * complicated to found for the end user.
12025 */
12026 errors = 0;
12027 list_for_each_entry(fcn, &referenced_functions, l) {
12028 ret = 0;
12029 for (i = 1; i < global.nbthread + 1; i++) {
12030 if (fcn->function_ref[i] == -1)
12031 ret--;
12032 else
12033 ret++;
12034 }
12035 if (abs(ret) != global.nbthread) {
12036 ha_alert("Lua function '%s' is not referenced in all thread. "
12037 "Expect function in all thread or in none thread.\n", fcn->name);
12038 errors++;
12039 continue;
12040 }
12041
12042 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050012043 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
12044 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +010012045 "exclusive.\n", fcn->name);
12046 errors++;
12047 }
12048 }
12049
Christopher Faulet69c581a2021-05-31 08:54:04 +020012050 /* Do the same with registered filters */
12051 list_for_each_entry(reg_flt, &referenced_filters, l) {
12052 ret = 0;
12053 for (i = 1; i < global.nbthread + 1; i++) {
12054 if (reg_flt->flt_ref[i] == -1)
12055 ret--;
12056 else
12057 ret++;
12058 }
12059 if (abs(ret) != global.nbthread) {
12060 ha_alert("Lua filter '%s' is not referenced in all thread. "
12061 "Expect function in all thread or in none thread.\n", reg_flt->name);
12062 errors++;
12063 continue;
12064 }
12065
12066 if ((reg_flt->flt_ref[0] == -1) == (ret < 0)) {
12067 ha_alert("Lua filter '%s' is referenced both ins shared Lua context (through lua-load) "
12068 "and per-thread Lua context (through lua-load-per-thread). these two context "
12069 "exclusive.\n", fcn->name);
12070 errors++;
12071 }
12072 }
12073
12074
Thierry Fournier59f11be2020-11-29 00:37:41 +010012075 if (errors > 0)
12076 return 0;
12077
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +050012078 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +010012079 * -1 in order to have probably a segfault if someone use it
12080 */
12081 hlua_state_id = -1;
12082
12083 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +010012084}
12085
Willy Tarreau32f61e22015-03-18 17:54:59 +010012086/* The memory allocator used by the Lua stack. <ud> is a pointer to the
12087 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
12088 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010012089 * allocation. <nsize> is the requested new size. A new allocation is
12090 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +010012091 * zero. This one verifies that the limits are respected but is optimized
12092 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreaua5efdff2021-10-22 16:00:02 +020012093 *
12094 * Warning: while this API ressembles glibc's realloc() a lot, glibc surpasses
12095 * POSIX by making realloc(ptr,0) an effective free(), but others do not do
12096 * that and will simply allocate zero as if it were the result of malloc(0),
12097 * so mapping this onto realloc() will lead to memory leaks on non-glibc
12098 * systems.
Willy Tarreau32f61e22015-03-18 17:54:59 +010012099 */
12100static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
12101{
12102 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +010012103 size_t limit, old, new;
12104
12105 /* a limit of ~0 means unlimited and boot complete, so there's no need
12106 * for accounting anymore.
12107 */
Willy Tarreaua5efdff2021-10-22 16:00:02 +020012108 if (likely(~zone->limit == 0)) {
12109 if (!nsize)
12110 ha_free(&ptr);
12111 else
12112 ptr = realloc(ptr, nsize);
12113 return ptr;
12114 }
Willy Tarreau32f61e22015-03-18 17:54:59 +010012115
Willy Tarreaud36c7fa2020-12-02 12:26:29 +010012116 if (!ptr)
12117 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +010012118
Willy Tarreaucdb53462020-12-02 12:12:00 +010012119 /* enforce strict limits across all threads */
12120 limit = zone->limit;
12121 old = _HA_ATOMIC_LOAD(&zone->allocated);
12122 do {
12123 new = old + nsize - osize;
12124 if (unlikely(nsize && limit && new > limit))
12125 return NULL;
12126 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +010012127
Willy Tarreaua5efdff2021-10-22 16:00:02 +020012128 if (!nsize)
12129 ha_free(&ptr);
12130 else
12131 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +010012132
12133 if (unlikely(!ptr && nsize)) // failed
12134 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
12135
12136 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +010012137 return ptr;
12138}
12139
Thierry Fournierecb83c22020-11-28 15:49:44 +010012140/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012141 * We are in the initialisation process of HAProxy, this abort() is
12142 * tolerated.
12143 */
Thierry Fournierecb83c22020-11-28 15:49:44 +010012144lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010012145{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012146 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012147 int idx;
12148 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012149 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012150 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +010012151 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012152 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012153 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +010012154 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012155
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012156 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012157 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012158
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012159 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012160 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +010012161 *context = NULL;
12162
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012163 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +020012164 * the Lua function can fail with an abort. We are in the initialisation
12165 * process of HAProxy, this abort() is tolerated.
12166 */
12167
Thierry Fournier3c539322020-11-28 16:05:05 +010012168 /* Call post initialisation function in safe environment. */
12169 if (setjmp(safe_ljmp_env) != 0) {
12170 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012171 if (lua_type(L, -1) == LUA_TSTRING)
12172 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010012173 else
12174 error_msg = "critical error";
12175 fprintf(stderr, "Lua init: %s.\n", error_msg);
12176 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +010012177 } else {
12178 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +010012179 }
12180
Thierry FOURNIER380d0932015-01-23 14:27:52 +010012181 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012182 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012183#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
12184#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
12185#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012186 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012187#endif
12188#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012189 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +010012190#endif
12191#undef HLUA_PREPEND_PATH_TOSTRING
12192#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012193
Thierry Fournier59f11be2020-11-29 00:37:41 +010012194 /* Apply configured prepend path */
12195 list_for_each_entry(pp, &prepend_path_list, l)
12196 hlua_prepend_path(L, pp->type, pp->path);
12197
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012198 /*
12199 *
12200 * Create "core" object.
12201 *
12202 */
12203
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +010012204 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012205 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012206
Thierry Fournierecb83c22020-11-28 15:49:44 +010012207 /* set the thread id */
12208 hlua_class_const_int(L, "thread", thread_num);
12209
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012210 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +010012211 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012212 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +010012213
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012214 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012215 hlua_class_function(L, "register_init", hlua_register_init);
12216 hlua_class_function(L, "register_task", hlua_register_task);
12217 hlua_class_function(L, "register_fetches", hlua_register_fetches);
12218 hlua_class_function(L, "register_converters", hlua_register_converters);
12219 hlua_class_function(L, "register_action", hlua_register_action);
12220 hlua_class_function(L, "register_service", hlua_register_service);
12221 hlua_class_function(L, "register_cli", hlua_register_cli);
Christopher Faulet69c581a2021-05-31 08:54:04 +020012222 hlua_class_function(L, "register_filter", hlua_register_filter);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012223 hlua_class_function(L, "yield", hlua_yield);
12224 hlua_class_function(L, "set_nice", hlua_set_nice);
12225 hlua_class_function(L, "sleep", hlua_sleep);
12226 hlua_class_function(L, "msleep", hlua_msleep);
12227 hlua_class_function(L, "add_acl", hlua_add_acl);
12228 hlua_class_function(L, "del_acl", hlua_del_acl);
12229 hlua_class_function(L, "set_map", hlua_set_map);
12230 hlua_class_function(L, "del_map", hlua_del_map);
12231 hlua_class_function(L, "tcp", hlua_socket_new);
William Lallemand3956c4e2021-09-21 16:25:15 +020012232 hlua_class_function(L, "httpclient", hlua_httpclient_new);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012233 hlua_class_function(L, "log", hlua_log);
12234 hlua_class_function(L, "Debug", hlua_log_debug);
12235 hlua_class_function(L, "Info", hlua_log_info);
12236 hlua_class_function(L, "Warning", hlua_log_warning);
12237 hlua_class_function(L, "Alert", hlua_log_alert);
12238 hlua_class_function(L, "done", hlua_done);
12239 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +010012240
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012241 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012242
12243 /*
12244 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012245 * Create "act" object.
12246 *
12247 */
12248
12249 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012250 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012251
12252 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012253 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
12254 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
12255 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
12256 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
12257 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
12258 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
12259 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
12260 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012261
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012262 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +010012263
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012264 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +010012265
12266 /*
12267 *
Christopher Faulet69c581a2021-05-31 08:54:04 +020012268 * Create "Filter" object.
12269 *
12270 */
12271
12272 /* This table entry is the object "filter" base. */
12273 lua_newtable(L);
12274
12275 /* push flags and constants */
12276 hlua_class_const_int(L, "CONTINUE", 1);
12277 hlua_class_const_int(L, "WAIT", 0);
12278 hlua_class_const_int(L, "ERROR", -1);
12279
12280 hlua_class_const_int(L, "FLT_CFG_FL_HTX", FLT_CFG_FL_HTX);
12281
Christopher Fauletc404f112020-02-26 15:03:09 +010012282 hlua_class_function(L, "wake_time", hlua_set_wake_time);
12283 hlua_class_function(L, "register_data_filter", hlua_register_data_filter);
12284 hlua_class_function(L, "unregister_data_filter", hlua_unregister_data_filter);
12285
Christopher Faulet69c581a2021-05-31 08:54:04 +020012286 lua_setglobal(L, "filter");
12287
12288 /*
12289 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012290 * Register class Map
12291 *
12292 */
12293
12294 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012295 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012296
12297 /* register pattern types. */
12298 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012299 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010012300 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012301 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012302 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +010012303 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012304
12305 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012306 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012307
12308 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012309 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012310
Ilya Shipitsind4259502020-04-08 01:07:56 +050012311 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012312 lua_pushstring(L, "__index");
12313 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012314
12315 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012316 hlua_class_function(L, "lookup", hlua_map_lookup);
12317 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012318
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012319 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012320
Thierry Fournier45e78d72016-02-19 18:34:46 +010012321 /* Register previous table in the registry with reference and named entry.
12322 * The function hlua_register_metatable() pops the stack, so we
12323 * previously create a copy of the table.
12324 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012325 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
12326 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012327
12328 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012329 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012330
12331 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012332 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +020012333
12334 /*
12335 *
William Lallemand30fcca12022-03-30 12:03:12 +020012336 * Register "CertCache" class
12337 *
12338 */
12339
12340 /* Create and fill the metatable. */
12341 lua_newtable(L);
12342 /* Register */
12343 hlua_class_function(L, "set", hlua_ckch_set);
12344 lua_setglobal(L, CLASS_CERTCACHE); /* Create global object called Regex */
12345
12346 /*
12347 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012348 * Register class Channel
12349 *
12350 */
12351
12352 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012353 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012354
Ilya Shipitsind4259502020-04-08 01:07:56 +050012355 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012356 lua_pushstring(L, "__index");
12357 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012358
12359 /* Register . */
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012360 hlua_class_function(L, "data", hlua_channel_get_data);
12361 hlua_class_function(L, "line", hlua_channel_get_line);
12362 hlua_class_function(L, "set", hlua_channel_set_data);
12363 hlua_class_function(L, "remove", hlua_channel_del_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012364 hlua_class_function(L, "append", hlua_channel_append);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012365 hlua_class_function(L, "prepend", hlua_channel_prepend);
12366 hlua_class_function(L, "insert", hlua_channel_insert_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012367 hlua_class_function(L, "send", hlua_channel_send);
12368 hlua_class_function(L, "forward", hlua_channel_forward);
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012369 hlua_class_function(L, "input", hlua_channel_get_in_len);
12370 hlua_class_function(L, "output", hlua_channel_get_out_len);
12371 hlua_class_function(L, "may_recv", hlua_channel_may_recv);
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012372 hlua_class_function(L, "is_full", hlua_channel_is_full);
12373 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012374
Christopher Faulet6a79fc12021-08-06 16:02:36 +020012375 /* Deprecated API */
12376 hlua_class_function(L, "get", hlua_channel_get);
12377 hlua_class_function(L, "dup", hlua_channel_dup);
12378 hlua_class_function(L, "getline", hlua_channel_getline);
12379 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
12380 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
12381
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012382 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012383
12384 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012385 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +010012386
12387 /*
12388 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012389 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012390 *
12391 */
12392
12393 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012394 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012395
Ilya Shipitsind4259502020-04-08 01:07:56 +050012396 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012397 lua_pushstring(L, "__index");
12398 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012399
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012400 /* Browse existing fetches and create the associated
12401 * object method.
12402 */
12403 sf = NULL;
12404 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012405 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
12406 * by an underscore.
12407 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020012408 strlcpy2(trash.area, sf->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012409 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012410 if (*p == '.' || *p == '-' || *p == '+')
12411 *p = '_';
12412
12413 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012414 lua_pushstring(L, trash.area);
12415 lua_pushlightuserdata(L, sf);
12416 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
12417 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +010012418 }
12419
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012420 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012421
12422 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012423 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012424
12425 /*
12426 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012427 * Register class Converters
12428 *
12429 */
12430
12431 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012432 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012433
12434 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012435 lua_pushstring(L, "__index");
12436 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012437
12438 /* Browse existing converters and create the associated
12439 * object method.
12440 */
12441 sc = NULL;
12442 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012443 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
12444 * by an underscore.
12445 */
Willy Tarreau5ef96562021-08-26 16:48:53 +020012446 strlcpy2(trash.area, sc->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +020012447 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012448 if (*p == '.' || *p == '-' || *p == '+')
12449 *p = '_';
12450
12451 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012452 lua_pushstring(L, trash.area);
12453 lua_pushlightuserdata(L, sc);
12454 lua_pushcclosure(L, hlua_run_sample_conv, 1);
12455 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012456 }
12457
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012458 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012459
12460 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012461 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +010012462
12463 /*
12464 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012465 * Register class HTTP
12466 *
12467 */
12468
12469 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012470 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012471
Ilya Shipitsind4259502020-04-08 01:07:56 +050012472 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012473 lua_pushstring(L, "__index");
12474 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012475
12476 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012477 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
12478 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
12479 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
12480 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
12481 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
12482 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
12483 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
12484 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
12485 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
12486 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012487
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012488 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
12489 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
12490 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
12491 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
12492 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
12493 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
12494 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012495
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012496 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012497
12498 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012499 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012500
Christopher Fauletdf97ac42020-02-26 16:57:19 +010012501 /*
12502 *
12503 * Register class HTTPMessage
12504 *
12505 */
12506
12507 /* Create and fill the metatable. */
12508 lua_newtable(L);
12509
Ilya Shipitsinff0f2782021-08-22 22:18:07 +050012510 /* Create and fill the __index entry. */
Christopher Fauletdf97ac42020-02-26 16:57:19 +010012511 lua_pushstring(L, "__index");
12512 lua_newtable(L);
12513
12514 /* Register Lua functions. */
12515 hlua_class_function(L, "is_resp", hlua_http_msg_is_resp);
12516 hlua_class_function(L, "get_stline", hlua_http_msg_get_stline);
12517 hlua_class_function(L, "get_headers", hlua_http_msg_get_headers);
12518 hlua_class_function(L, "del_header", hlua_http_msg_del_hdr);
12519 hlua_class_function(L, "rep_header", hlua_http_msg_rep_hdr);
12520 hlua_class_function(L, "rep_value", hlua_http_msg_rep_val);
12521 hlua_class_function(L, "add_header", hlua_http_msg_add_hdr);
12522 hlua_class_function(L, "set_header", hlua_http_msg_set_hdr);
12523 hlua_class_function(L, "set_method", hlua_http_msg_set_meth);
12524 hlua_class_function(L, "set_path", hlua_http_msg_set_path);
12525 hlua_class_function(L, "set_query", hlua_http_msg_set_query);
12526 hlua_class_function(L, "set_uri", hlua_http_msg_set_uri);
12527 hlua_class_function(L, "set_status", hlua_http_msg_set_status);
12528 hlua_class_function(L, "is_full", hlua_http_msg_is_full);
12529 hlua_class_function(L, "may_recv", hlua_http_msg_may_recv);
12530 hlua_class_function(L, "eom", hlua_http_msg_is_eom);
12531 hlua_class_function(L, "input", hlua_http_msg_get_in_len);
12532 hlua_class_function(L, "output", hlua_http_msg_get_out_len);
12533
12534 hlua_class_function(L, "body", hlua_http_msg_get_body);
12535 hlua_class_function(L, "set", hlua_http_msg_set_data);
12536 hlua_class_function(L, "remove", hlua_http_msg_del_data);
12537 hlua_class_function(L, "append", hlua_http_msg_append);
12538 hlua_class_function(L, "prepend", hlua_http_msg_prepend);
12539 hlua_class_function(L, "insert", hlua_http_msg_insert_data);
12540 hlua_class_function(L, "set_eom", hlua_http_msg_set_eom);
12541 hlua_class_function(L, "unset_eom", hlua_http_msg_unset_eom);
12542
12543 hlua_class_function(L, "send", hlua_http_msg_send);
12544 hlua_class_function(L, "forward", hlua_http_msg_forward);
12545
12546 lua_rawset(L, -3);
12547
12548 /* Register previous table in the registry with reference and named entry. */
12549 class_http_msg_ref = hlua_register_metatable(L, CLASS_HTTP_MSG);
William Lallemand3956c4e2021-09-21 16:25:15 +020012550
12551 /*
12552 *
12553 * Register class HTTPClient
12554 *
12555 */
12556
12557 /* Create and fill the metatable. */
12558 lua_newtable(L);
12559 lua_pushstring(L, "__index");
12560 lua_newtable(L);
12561 hlua_class_function(L, "get", hlua_httpclient_get);
William Lallemanddc2cc902021-10-26 11:43:26 +020012562 hlua_class_function(L, "head", hlua_httpclient_head);
12563 hlua_class_function(L, "put", hlua_httpclient_put);
12564 hlua_class_function(L, "post", hlua_httpclient_post);
12565 hlua_class_function(L, "delete", hlua_httpclient_delete);
William Lallemand3956c4e2021-09-21 16:25:15 +020012566 lua_settable(L, -3); /* Sets the __index entry. */
William Lallemandf77f1de2021-09-28 19:10:38 +020012567 /* Register the garbage collector entry. */
12568 lua_pushstring(L, "__gc");
12569 lua_pushcclosure(L, hlua_httpclient_gc, 0);
12570 lua_settable(L, -3); /* Push the last 2 entries in the table at index -3 */
12571
William Lallemand3956c4e2021-09-21 16:25:15 +020012572
12573
12574 class_httpclient_ref = hlua_register_metatable(L, CLASS_HTTPCLIENT);
Thierry FOURNIER08504f42015-03-16 14:17:08 +010012575 /*
12576 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012577 * Register class AppletTCP
12578 *
12579 */
12580
12581 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012582 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012583
Ilya Shipitsind4259502020-04-08 01:07:56 +050012584 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012585 lua_pushstring(L, "__index");
12586 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012587
12588 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012589 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
12590 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
12591 hlua_class_function(L, "send", hlua_applet_tcp_send);
12592 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
12593 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
12594 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
12595 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
12596 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012597
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012598 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012599
12600 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012601 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +020012602
12603 /*
12604 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012605 * Register class AppletHTTP
12606 *
12607 */
12608
12609 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012610 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012611
Ilya Shipitsind4259502020-04-08 01:07:56 +050012612 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012613 lua_pushstring(L, "__index");
12614 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012615
12616 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012617 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
12618 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
12619 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
12620 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
12621 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
12622 hlua_class_function(L, "getline", hlua_applet_http_getline);
12623 hlua_class_function(L, "receive", hlua_applet_http_recv);
12624 hlua_class_function(L, "send", hlua_applet_http_send);
12625 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
12626 hlua_class_function(L, "set_status", hlua_applet_http_status);
12627 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012628
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012629 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012630
12631 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012632 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +020012633
12634 /*
12635 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012636 * Register class TXN
12637 *
12638 */
12639
12640 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012641 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012642
Ilya Shipitsind4259502020-04-08 01:07:56 +050012643 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012644 lua_pushstring(L, "__index");
12645 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +010012646
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010012647 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012648 hlua_class_function(L, "set_priv", hlua_set_priv);
12649 hlua_class_function(L, "get_priv", hlua_get_priv);
12650 hlua_class_function(L, "set_var", hlua_set_var);
12651 hlua_class_function(L, "unset_var", hlua_unset_var);
12652 hlua_class_function(L, "get_var", hlua_get_var);
12653 hlua_class_function(L, "done", hlua_txn_done);
12654 hlua_class_function(L, "reply", hlua_txn_reply_new);
12655 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
12656 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
12657 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
12658 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
12659 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
12660 hlua_class_function(L, "deflog", hlua_txn_deflog);
12661 hlua_class_function(L, "log", hlua_txn_log);
12662 hlua_class_function(L, "Debug", hlua_txn_log_debug);
12663 hlua_class_function(L, "Info", hlua_txn_log_info);
12664 hlua_class_function(L, "Warning", hlua_txn_log_warning);
12665 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +010012666
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012667 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +010012668
12669 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012670 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012671
12672 /*
12673 *
Christopher Faulet700d9e82020-01-31 12:21:52 +010012674 * Register class reply
12675 *
12676 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012677 lua_newtable(L);
12678 lua_pushstring(L, "__index");
12679 lua_newtable(L);
12680 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
12681 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
12682 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
12683 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
12684 lua_settable(L, -3); /* Sets the __index entry. */
12685 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +010012686
12687
12688 /*
12689 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012690 * Register class Socket
12691 *
12692 */
12693
12694 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012695 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012696
Ilya Shipitsind4259502020-04-08 01:07:56 +050012697 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012698 lua_pushstring(L, "__index");
12699 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012700
Baptiste Assmann84bb4932015-03-02 21:40:06 +010012701#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012702 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +010012703#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012704 hlua_class_function(L, "connect", hlua_socket_connect);
12705 hlua_class_function(L, "send", hlua_socket_send);
12706 hlua_class_function(L, "receive", hlua_socket_receive);
12707 hlua_class_function(L, "close", hlua_socket_close);
12708 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
12709 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
12710 hlua_class_function(L, "setoption", hlua_socket_setoption);
12711 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012712
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012713 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012714
12715 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012716 lua_pushstring(L, "__gc");
12717 lua_pushcclosure(L, hlua_socket_gc, 0);
12718 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012719
12720 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010012721 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012722
Thierry Fournieraafc7772020-12-04 11:47:47 +010012723 lua_atpanic(L, hlua_panic_safe);
12724
12725 return L;
12726}
12727
12728void hlua_init(void) {
12729 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012730 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +010012731#ifdef USE_OPENSSL
12732 struct srv_kw *kw;
12733 int tmp_error;
12734 char *error;
12735 char *args[] = { /* SSL client configuration. */
12736 "ssl",
12737 "verify",
12738 "none",
12739 NULL
12740 };
12741#endif
12742
12743 /* Init post init function list head */
12744 for (i = 0; i < MAX_THREADS + 1; i++)
12745 LIST_INIT(&hlua_init_functions[i]);
12746
12747 /* Init state for common/shared lua parts */
12748 hlua_state_id = 0;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012749 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010012750 hlua_states[0] = hlua_init_state(0);
12751
12752 /* Init state 1 for thread 0. We have at least one thread. */
12753 hlua_state_id = 1;
Willy Tarreau43ab05b2021-09-28 09:43:11 +020012754 ha_set_thread(NULL);
Thierry Fournieraafc7772020-12-04 11:47:47 +010012755 hlua_states[1] = hlua_init_state(1);
12756
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012757 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +020012758 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012759 if (!socket_proxy) {
12760 fprintf(stderr, "Lua init: %s\n", errmsg);
12761 exit(1);
12762 }
12763 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012764
12765 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012766 socket_tcp = new_server(socket_proxy);
12767 if (!socket_tcp) {
12768 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
12769 exit(1);
12770 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012771
12772#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012773 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012774 socket_ssl = new_server(socket_proxy);
12775 if (!socket_ssl) {
12776 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
12777 exit(1);
12778 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012779
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012780 socket_ssl->use_ssl = 1;
12781 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012782
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000012783 for (i = 0; args[i] != NULL; i++) {
12784 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012785 /*
12786 *
12787 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080012788 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012789 * features like client certificates and ssl_verify.
12790 *
12791 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010012792 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012793 if (tmp_error != 0) {
12794 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
12795 abort(); /* This must be never arrives because the command line
12796 not editable by the user. */
12797 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000012798 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012799 }
12800 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010012801#endif
Thierry Fournier75933d42016-01-21 09:30:18 +010012802
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010012803}
Willy Tarreaubb57d942016-12-21 19:04:56 +010012804
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020012805static void hlua_deinit()
12806{
Willy Tarreau186f3762020-12-04 11:48:12 +010012807 int thr;
Christopher Faulet69c581a2021-05-31 08:54:04 +020012808 struct hlua_reg_filter *reg_flt, *reg_flt_bck;
12809
12810 list_for_each_entry_safe(reg_flt, reg_flt_bck, &referenced_filters, l)
12811 release_hlua_reg_filter(reg_flt);
Willy Tarreau186f3762020-12-04 11:48:12 +010012812
12813 for (thr = 0; thr < MAX_THREADS+1; thr++) {
12814 if (hlua_states[thr])
12815 lua_close(hlua_states[thr]);
12816 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +010012817
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020012818 srv_drop(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +010012819
Willy Tarreau0f143af2021-03-05 10:41:48 +010012820#ifdef USE_OPENSSL
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +020012821 srv_drop(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +010012822#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010012823
12824 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020012825}
12826
12827REGISTER_POST_DEINIT(hlua_deinit);
12828
Willy Tarreau80713382018-11-26 10:19:54 +010012829static void hlua_register_build_options(void)
12830{
Willy Tarreaubb57d942016-12-21 19:04:56 +010012831 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +010012832
Willy Tarreaubb57d942016-12-21 19:04:56 +010012833 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
12834 hap_register_build_opts(ptr, 1);
12835}
Willy Tarreau80713382018-11-26 10:19:54 +010012836
12837INITCALL0(STG_REGISTER, hlua_register_build_options);