blob: 82445930ea0165583fed17dadca52daa4135ecc3 [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 Jacquin3dfbd272021-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 Tarreau7ea393d2020-06-04 18:02:10 +020035#include <haproxy/connection.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020036#include <haproxy/h1.h>
Willy Tarreau86416052020-06-04 09:20:54 +020037#include <haproxy/hlua.h>
Willy Tarreau8c794002020-06-04 10:05:25 +020038#include <haproxy/hlua_fcn.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020039#include <haproxy/http_ana.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020040#include <haproxy/http_fetch.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/http_htx.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020042#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020043#include <haproxy/log.h>
Willy Tarreau2cd58092020-06-04 15:10:43 +020044#include <haproxy/map.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020045#include <haproxy/obj_type.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020046#include <haproxy/pattern.h>
Willy Tarreau469509b2020-06-04 15:13:30 +020047#include <haproxy/payload.h>
Willy Tarreaua264d962020-06-04 22:29:18 +020048#include <haproxy/proxy-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020049#include <haproxy/regex.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020050#include <haproxy/sample.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +020051#include <haproxy/server-t.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +020052#include <haproxy/session.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020053#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020054#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020055#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020056#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020057#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020058#include <haproxy/thread.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020059#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020060#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020061#include <haproxy/xref.h>
62
Thierry FOURNIER380d0932015-01-23 14:27:52 +010063
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010064/* Lua uses longjmp to perform yield or throwing errors. This
65 * macro is used only for identifying the function that can
66 * not return because a longjmp is executed.
67 * __LJMP marks a prototype of hlua file that can use longjmp.
68 * WILL_LJMP() marks an lua function that will use longjmp.
69 * MAY_LJMP() marks an lua function that may use longjmp.
70 */
71#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020072#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010073#define MAY_LJMP(func) func
74
Thierry FOURNIERbabae282015-09-17 11:36:37 +020075/* This couple of function executes securely some Lua calls outside of
76 * the lua runtime environment. Each Lua call can return a longjmp
77 * if it encounter a memory error.
78 *
79 * Lua documentation extract:
80 *
81 * If an error happens outside any protected environment, Lua calls
82 * a panic function (see lua_atpanic) and then calls abort, thus
83 * exiting the host application. Your panic function can avoid this
84 * exit by never returning (e.g., doing a long jump to your own
85 * recovery point outside Lua).
86 *
87 * The panic function runs as if it were a message handler (see
88 * §2.3); in particular, the error message is at the top of the
89 * stack. However, there is no guarantee about stack space. To push
90 * anything on the stack, the panic function must first check the
91 * available space (see §4.2).
92 *
93 * We must check all the Lua entry point. This includes:
94 * - The include/proto/hlua.h exported functions
95 * - the task wrapper function
96 * - The action wrapper function
97 * - The converters wrapper function
98 * - The sample-fetch wrapper functions
99 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500100 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800101 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200102 *
103 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
104 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
105 * because they must be exists in the program stack when the longjmp
106 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200107 *
108 * Note that the Lua processing is not really thread safe. It provides
109 * heavy system which consists to add our own lock function in the Lua
110 * code and recompile the library. This system will probably not accepted
111 * by maintainers of various distribs.
112 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500113 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200114 * quick looking on the Lua sources displays a lua_lock() a the start
115 * of function and a lua_unlock() at the end of the function. So I
116 * conclude that the Lua thread safe mode just perform a mutex around
117 * all execution. So I prefer to do this in the HAProxy code, it will be
118 * easier for distro maintainers.
119 *
120 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
121 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
122 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200123 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100124__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200125THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200126static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau9d6bb5a2020-02-06 15:55:41 +0100127static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200128
129#define SET_SAFE_LJMP(__L) \
130 ({ \
131 int ret; \
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100132 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200133 if (setjmp(safe_ljmp_env) != 0) { \
134 lua_atpanic(__L, hlua_panic_safe); \
135 ret = 0; \
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100136 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200137 } else { \
138 lua_atpanic(__L, hlua_panic_ljmp); \
139 ret = 1; \
140 } \
141 ret; \
142 })
143
144/* If we are the last function catching Lua errors, we
145 * must reset the panic function.
146 */
147#define RESET_SAFE_LJMP(__L) \
148 do { \
149 lua_atpanic(__L, hlua_panic_safe); \
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100150 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200151 } while(0)
152
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200153/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200154#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100155/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200156#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200157/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100158#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100159#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200160
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100161/* The main Lua execution context. */
162struct hlua gL;
163
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100164/* This is the memory pool containing struct lua for applets
165 * (including cli).
166 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100167DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100168
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100169/* Used for Socket connection. */
170static struct proxy socket_proxy;
171static struct server socket_tcp;
172#ifdef USE_OPENSSL
173static struct server socket_ssl;
174#endif
175
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100176/* List head of the function called at the initialisation time. */
177struct list hlua_init_functions = LIST_HEAD_INIT(hlua_init_functions);
178
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100179/* The following variables contains the reference of the different
180 * Lua classes. These references are useful for identify metadata
181 * associated with an object.
182 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100183static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100184static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100185static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100186static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100187static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100188static int class_http_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200189static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200190static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200191static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100192static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100193
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100194/* Global Lua execution timeout. By default Lua, execution linked
Willy Tarreau87b09662015-04-03 00:22:06 +0200195 * with stream (actions, sample-fetches and converters) have a
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100196 * short timeout. Lua linked with tasks doesn't have a timeout
197 * because a task may remain alive during all the haproxy execution.
198 */
199static unsigned int hlua_timeout_session = 4000; /* session timeout. */
200static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200201static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100202
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100203/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
204 * it is used for preventing infinite loops.
205 *
206 * I test the scheer with an infinite loop containing one incrementation
207 * and one test. I run this loop between 10 seconds, I raise a ceil of
208 * 710M loops from one interrupt each 9000 instructions, so I fix the value
209 * to one interrupt each 10 000 instructions.
210 *
211 * configured | Number of
212 * instructions | loops executed
213 * between two | in milions
214 * forced yields |
215 * ---------------+---------------
216 * 10 | 160
217 * 500 | 670
218 * 1000 | 680
219 * 5000 | 700
220 * 7000 | 700
221 * 8000 | 700
222 * 9000 | 710 <- ceil
223 * 10000 | 710
224 * 100000 | 710
225 * 1000000 | 710
226 *
227 */
228static unsigned int hlua_nb_instruction = 10000;
229
Willy Tarreau32f61e22015-03-18 17:54:59 +0100230/* Descriptor for the memory allocation state. If limit is not null, it will
231 * be enforced on any memory allocation.
232 */
233struct hlua_mem_allocator {
234 size_t allocated;
235 size_t limit;
236};
237
238static struct hlua_mem_allocator hlua_global_allocator;
239
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100240/* These functions converts types between HAProxy internal args or
241 * sample and LUA types. Another function permits to check if the
242 * LUA stack contains arguments according with an required ARG_T
243 * format.
244 */
245static int hlua_arg2lua(lua_State *L, const struct arg *arg);
246static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100247__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100248 uint64_t mask, struct proxy *p);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100249static int hlua_smp2lua(lua_State *L, struct sample *smp);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100250static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100251static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
252
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100253__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200254
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200255#define SEND_ERR(__be, __fmt, __args...) \
256 do { \
257 send_log(__be, LOG_ERR, __fmt, ## __args); \
258 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100259 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200260 } while (0)
261
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100262/* Used to check an Lua function type in the stack. It creates and
263 * returns a reference of the function. This function throws an
264 * error if the rgument is not a "function".
265 */
266__LJMP unsigned int hlua_checkfunction(lua_State *L, int argno)
267{
268 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100269 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100270 WILL_LJMP(luaL_argerror(L, argno, msg));
271 }
272 lua_pushvalue(L, argno);
273 return luaL_ref(L, LUA_REGISTRYINDEX);
274}
275
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200276/* Return the string that is of the top of the stack. */
277const char *hlua_get_top_error_string(lua_State *L)
278{
279 if (lua_gettop(L) < 1)
280 return "unknown error";
281 if (lua_type(L, -1) != LUA_TSTRING)
282 return "unknown error";
283 return lua_tostring(L, -1);
284}
285
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200286__LJMP static const char *hlua_traceback(lua_State *L)
287{
288 lua_Debug ar;
289 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200290 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200291 int filled = 0;
292
293 while (lua_getstack(L, level++, &ar)) {
294
295 /* Add separator */
296 if (filled)
297 chunk_appendf(msg, ", ");
298 filled = 1;
299
300 /* Fill fields:
301 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
302 * 'l': fills in the field currentline;
303 * 'n': fills in the field name and namewhat;
304 * 't': fills in the field istailcall;
305 */
306 lua_getinfo(L, "Slnt", &ar);
307
308 /* Append code localisation */
309 if (ar.currentline > 0)
310 chunk_appendf(msg, "%s:%d ", ar.short_src, ar.currentline);
311 else
312 chunk_appendf(msg, "%s ", ar.short_src);
313
314 /*
315 * Get function name
316 *
317 * if namewhat is no empty, name is defined.
318 * what contains "Lua" for Lua function, "C" for C function,
319 * or "main" for main code.
320 */
321 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
322 chunk_appendf(msg, "%s '%s'", ar.namewhat, ar.name); /* use it */
323
324 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
325 chunk_appendf(msg, "main chunk");
326
327 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
328 chunk_appendf(msg, "C function line %d", ar.linedefined);
329
330 else /* nothing left... */
331 chunk_appendf(msg, "?");
332
333
334 /* Display tailed call */
335 if (ar.istailcall)
336 chunk_appendf(msg, " ...");
337 }
338
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200339 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200340}
341
342
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100343/* This function check the number of arguments available in the
344 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500345 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100346 */
347__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
348{
349 if (lua_gettop(L) == nb)
350 return;
351 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
352}
353
Mark Lakes22154b42018-01-29 14:38:40 -0800354/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100355 * and the line number where the error is encountered.
356 */
357static int hlua_pusherror(lua_State *L, const char *fmt, ...)
358{
359 va_list argp;
360 va_start(argp, fmt);
361 luaL_where(L, 1);
362 lua_pushvfstring(L, fmt, argp);
363 va_end(argp);
364 lua_concat(L, 2);
365 return 1;
366}
367
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100368/* This functions is used with sample fetch and converters. It
369 * converts the HAProxy configuration argument in a lua stack
370 * values.
371 *
372 * It takes an array of "arg", and each entry of the array is
373 * converted and pushed in the LUA stack.
374 */
375static int hlua_arg2lua(lua_State *L, const struct arg *arg)
376{
377 switch (arg->type) {
378 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100379 case ARGT_TIME:
380 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100381 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100382 break;
383
384 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200385 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100386 break;
387
388 case ARGT_IPV4:
389 case ARGT_IPV6:
390 case ARGT_MSK4:
391 case ARGT_MSK6:
392 case ARGT_FE:
393 case ARGT_BE:
394 case ARGT_TAB:
395 case ARGT_SRV:
396 case ARGT_USR:
397 case ARGT_MAP:
398 default:
399 lua_pushnil(L);
400 break;
401 }
402 return 1;
403}
404
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500405/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100406 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500407 * with sample fetch wrappers. The input arguments are given to the
408 * lua wrapper and converted as arg list by the function.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100409 */
410static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
411{
412 switch (lua_type(L, ud)) {
413
414 case LUA_TNUMBER:
415 case LUA_TBOOLEAN:
416 arg->type = ARGT_SINT;
417 arg->data.sint = lua_tointeger(L, ud);
418 break;
419
420 case LUA_TSTRING:
421 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200422 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200423 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200424 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200425 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100426 break;
427
428 case LUA_TUSERDATA:
429 case LUA_TNIL:
430 case LUA_TTABLE:
431 case LUA_TFUNCTION:
432 case LUA_TTHREAD:
433 case LUA_TLIGHTUSERDATA:
434 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200435 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100436 break;
437 }
438 return 1;
439}
440
441/* the following functions are used to convert a struct sample
442 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500443 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100444 */
Willy Tarreau5eadada2015-03-10 17:28:54 +0100445static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100446{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200447 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100448 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100449 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200450 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100451 break;
452
453 case SMP_T_BIN:
454 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200455 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100456 break;
457
458 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200459 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100460 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
461 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
462 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
463 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
464 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
465 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
466 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
467 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
468 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200469 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100470 break;
471 default:
472 lua_pushnil(L);
473 break;
474 }
475 break;
476
477 case SMP_T_IPV4:
478 case SMP_T_IPV6:
479 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200480 if (sample_casts[smp->data.type][SMP_T_STR] &&
481 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200482 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100483 else
484 lua_pushnil(L);
485 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100486 default:
487 lua_pushnil(L);
488 break;
489 }
490 return 1;
491}
492
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100493/* the following functions are used to convert a struct sample
494 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500495 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100496 */
497static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
498{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200499 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100500
501 case SMP_T_BIN:
502 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200503 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100504 break;
505
506 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200507 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100508 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
509 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
510 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
511 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
512 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
513 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
514 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
515 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
516 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200517 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100518 break;
519 default:
520 lua_pushstring(L, "");
521 break;
522 }
523 break;
524
525 case SMP_T_SINT:
526 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100527 case SMP_T_IPV4:
528 case SMP_T_IPV6:
529 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200530 if (sample_casts[smp->data.type][SMP_T_STR] &&
531 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200532 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100533 else
534 lua_pushstring(L, "");
535 break;
536 default:
537 lua_pushstring(L, "");
538 break;
539 }
540 return 1;
541}
542
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100543/* the following functions are used to convert an Lua type in a
544 * struct sample. This is useful to provide data from a converter
545 * to the LUA code.
546 */
547static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
548{
549 switch (lua_type(L, ud)) {
550
551 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200552 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200553 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100554 break;
555
556
557 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200558 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200559 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100560 break;
561
562 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200563 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100564 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200565 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200566 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200567 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200568 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100569 break;
570
571 case LUA_TUSERDATA:
572 case LUA_TNIL:
573 case LUA_TTABLE:
574 case LUA_TFUNCTION:
575 case LUA_TTHREAD:
576 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +0200577 case LUA_TNONE:
578 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200579 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200580 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100581 break;
582 }
583 return 1;
584}
585
Ilya Shipitsind4259502020-04-08 01:07:56 +0500586/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800587 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100588 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100589 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500590 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100591 * entries.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100592 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100593__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100594 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100595{
596 int min_arg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200597 int i, idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100598 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +0200599 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200600 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200601 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200602 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100603
604 idx = 0;
605 min_arg = ARGM(mask);
606 mask >>= ARGM_BITS;
607
608 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200609 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100610
611 /* Check oversize. */
612 if (idx >= ARGM_NBARGS && argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200613 msg = "Malformed argument mask";
614 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100615 }
616
617 /* Check for mandatory arguments. */
618 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100619 if (idx < min_arg) {
620
621 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200622 if (idx > 0) {
623 msg = "Mandatory argument expected";
624 goto error;
625 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100626
627 /* If first argument have a certain type, some default values
628 * may be used. See the function smp_resolve_args().
629 */
630 switch (mask & ARGT_MASK) {
631
632 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200633 if (!(p->cap & PR_CAP_FE)) {
634 msg = "Mandatory argument expected";
635 goto error;
636 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100637 argp[idx].data.prx = p;
638 argp[idx].type = ARGT_FE;
639 argp[idx+1].type = ARGT_STOP;
640 break;
641
642 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200643 if (!(p->cap & PR_CAP_BE)) {
644 msg = "Mandatory argument expected";
645 goto error;
646 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100647 argp[idx].data.prx = p;
648 argp[idx].type = ARGT_BE;
649 argp[idx+1].type = ARGT_STOP;
650 break;
651
652 case ARGT_TAB:
653 argp[idx].data.prx = p;
654 argp[idx].type = ARGT_TAB;
655 argp[idx+1].type = ARGT_STOP;
656 break;
657
658 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200659 msg = "Mandatory argument expected";
660 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100661 break;
662 }
663 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200664 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100665 }
666
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500667 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100668 if ((mask & ARGT_MASK) == ARGT_STOP &&
669 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200670 msg = "Last argument expected";
671 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100672 }
673
674 if ((mask & ARGT_MASK) == ARGT_STOP &&
675 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200676 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100677 }
678
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200679 /* Convert some argument types. All string in argp[] are for not
680 * duplicated yet.
681 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100682 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100683 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200684 if (argp[idx].type != ARGT_SINT) {
685 msg = "integer expected";
686 goto error;
687 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100688 argp[idx].type = ARGT_SINT;
689 break;
690
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100691 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200692 if (argp[idx].type != ARGT_SINT) {
693 msg = "integer expected";
694 goto error;
695 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200696 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100697 break;
698
699 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200700 if (argp[idx].type != ARGT_SINT) {
701 msg = "integer expected";
702 goto error;
703 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200704 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100705 break;
706
707 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200708 if (argp[idx].type != ARGT_STR) {
709 msg = "string expected";
710 goto error;
711 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200712 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200713 if (!argp[idx].data.prx) {
714 msg = "frontend doesn't exist";
715 goto error;
716 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100717 argp[idx].type = ARGT_FE;
718 break;
719
720 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200721 if (argp[idx].type != ARGT_STR) {
722 msg = "string expected";
723 goto error;
724 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200725 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200726 if (!argp[idx].data.prx) {
727 msg = "backend doesn't exist";
728 goto error;
729 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100730 argp[idx].type = ARGT_BE;
731 break;
732
733 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200734 if (argp[idx].type != ARGT_STR) {
735 msg = "string expected";
736 goto error;
737 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200738 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200739 if (!argp[idx].data.t) {
740 msg = "table doesn't exist";
741 goto error;
742 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100743 argp[idx].type = ARGT_TAB;
744 break;
745
746 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200747 if (argp[idx].type != ARGT_STR) {
748 msg = "string expected";
749 goto error;
750 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200751 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100752 if (sname) {
753 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200754 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +0200755 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200756 if (!px) {
757 msg = "backend doesn't exist";
758 goto error;
759 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100760 }
761 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200762 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100763 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100764 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100765 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200766 if (!argp[idx].data.srv) {
767 msg = "server doesn't exist";
768 goto error;
769 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100770 argp[idx].type = ARGT_SRV;
771 break;
772
773 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200774 if (argp[idx].type != ARGT_STR) {
775 msg = "string expected";
776 goto error;
777 }
778 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
779 msg = "invalid IPv4 address";
780 goto error;
781 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100782 argp[idx].type = ARGT_IPV4;
783 break;
784
785 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200786 if (argp[idx].type == ARGT_SINT)
787 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
788 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200789 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
790 msg = "invalid IPv4 mask";
791 goto error;
792 }
793 }
794 else {
795 msg = "integer or string expected";
796 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200797 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100798 argp[idx].type = ARGT_MSK4;
799 break;
800
801 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200802 if (argp[idx].type != ARGT_STR) {
803 msg = "string expected";
804 goto error;
805 }
806 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
807 msg = "invalid IPv6 address";
808 goto error;
809 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100810 argp[idx].type = ARGT_IPV6;
811 break;
812
813 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200814 if (argp[idx].type == ARGT_SINT)
815 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
816 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200817 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
818 msg = "invalid IPv6 mask";
819 goto error;
820 }
821 }
822 else {
823 msg = "integer or string expected";
824 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200825 }
Tim Duesterhusb814da62018-01-25 16:24:50 +0100826 argp[idx].type = ARGT_MSK6;
827 break;
828
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200829 case ARGT_REG:
830 if (argp[idx].type != ARGT_STR) {
831 msg = "string expected";
832 goto error;
833 }
834 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
835 if (!reg) {
836 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
837 argp[idx].data.str.area, err);
838 free(err);
839 goto error;
840 }
841 argp[idx].type = ARGT_REG;
842 argp[idx].data.reg = reg;
843 break;
844
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100845 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +0200846 if (argp[idx].type != ARGT_STR) {
847 msg = "string expected";
848 goto error;
849 }
850 if (p->uri_auth && p->uri_auth->userlist &&
851 !strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area))
852 ul = p->uri_auth->userlist;
853 else
854 ul = auth_find_userlist(argp[idx].data.str.area);
855
856 if (!ul) {
857 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
858 goto error;
859 }
860 argp[idx].type = ARGT_USR;
861 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200862 break;
863
864 case ARGT_STR:
865 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
866 msg = "unable to duplicate string arg";
867 goto error;
868 }
869 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100870 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200871
Christopher Fauletd25d9262020-08-06 11:04:46 +0200872 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +0200873 msg = "type not yet supported";
874 goto error;
875 break;
876
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100877 }
878
879 /* Check for type of argument. */
880 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200881 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
882 arg_type_names[(mask & ARGT_MASK)],
883 arg_type_names[argp[idx].type & ARGT_MASK]);
884 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100885 }
886
887 /* Next argument. */
888 mask >>= ARGT_BITS;
889 idx++;
890 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200891 return 0;
892
893 error:
894 for (i = 0; i < idx; i++) {
895 if (argp[i].type == ARGT_STR)
896 chunk_destroy(&argp[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200897 else if (argp[i].type == ARGT_REG)
898 regex_free(argp[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200899 }
900 WILL_LJMP(luaL_argerror(L, first + idx, msg));
901 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100902}
903
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100904/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500905 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100906 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100907 *
908 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100909 * - hlua_sethlua : create the association between hlua context and lua_state.
910 */
911static inline struct hlua *hlua_gethlua(lua_State *L)
912{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +0100913 struct hlua **hlua = lua_getextraspace(L);
914 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100915}
916static inline void hlua_sethlua(struct hlua *hlua)
917{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +0100918 struct hlua **hlua_store = lua_getextraspace(hlua->T);
919 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100920}
921
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +0100922/* This function is used to send logs. It try to send on screen (stderr)
923 * and on the default syslog server.
924 */
925static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
926{
927 struct tm tm;
928 char *p;
929
930 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200931 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +0100932 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200933 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +0200934 /* Break the message if exceed the buffer size. */
935 *(p-4) = ' ';
936 *(p-3) = '.';
937 *(p-2) = '.';
938 *(p-1) = '.';
939 break;
940 }
Willy Tarreau90807112020-02-25 08:16:33 +0100941 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +0100942 *p = *msg;
943 else
944 *p = '.';
945 }
946 *p = '\0';
947
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200948 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +0100949 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +0200950 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
951 return;
952
Willy Tarreaua678b432015-08-28 10:14:59 +0200953 get_localtime(date.tv_sec, &tm);
954 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +0100955 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200956 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +0100957 fflush(stderr);
958 }
959}
960
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +0100961/* This function just ensure that the yield will be always
962 * returned with a timeout and permit to set some flags
963 */
964__LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100965 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +0100966{
967 struct hlua *hlua = hlua_gethlua(L);
968
969 /* Set the wake timeout. If timeout is required, we set
970 * the expiration time.
971 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +0200972 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +0100973
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +0100974 hlua->flags |= flags;
975
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +0100976 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +0200977 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +0100978}
979
Willy Tarreau87b09662015-04-03 00:22:06 +0200980/* This function initialises the Lua environment stored in the stream.
981 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100982 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200983 *
984 * This function is particular. it initialises a new Lua thread. If the
985 * initialisation fails (example: out of memory error), the lua function
986 * throws an error (longjmp).
987 *
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +0100988 * In some case (at least one), this function can be called from safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500989 * environment, so we must not initialise it. While the support of
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +0100990 * threads appear, the safe environment set a lock to ensure only one
991 * Lua execution at a time. If we initialize safe environment in another
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500992 * safe environment, we have a dead lock.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +0100993 *
994 * set "already_safe" true if the context is initialized form safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500995 * Lua function.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +0100996 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800997 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200998 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800999 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001000 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001001 */
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001002int hlua_ctx_init(struct hlua *lua, struct task *task, int already_safe)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001003{
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001004 if (!already_safe) {
1005 if (!SET_SAFE_LJMP(gL.T)) {
1006 lua->Tref = LUA_REFNIL;
1007 return 0;
1008 }
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001009 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001010 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001011 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001012 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001013 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001014 LIST_INIT(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001015 lua->T = lua_newthread(gL.T);
1016 if (!lua->T) {
1017 lua->Tref = LUA_REFNIL;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001018 if (!already_safe)
1019 RESET_SAFE_LJMP(gL.T);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001020 return 0;
1021 }
1022 hlua_sethlua(lua);
1023 lua->Tref = luaL_ref(gL.T, LUA_REGISTRYINDEX);
1024 lua->task = task;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001025 if (!already_safe)
1026 RESET_SAFE_LJMP(gL.T);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001027 return 1;
1028}
1029
Willy Tarreau87b09662015-04-03 00:22:06 +02001030/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001031 * is destroyed. The destroy also the memory context. The struct "lua"
1032 * is not freed.
1033 */
1034void hlua_ctx_destroy(struct hlua *lua)
1035{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001036 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001037 return;
1038
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001039 if (!lua->T)
1040 goto end;
1041
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001042 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001043 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001044
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001045 if (!SET_SAFE_LJMP(lua->T))
1046 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001047 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001048 RESET_SAFE_LJMP(lua->T);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001049
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001050 if (!SET_SAFE_LJMP(gL.T))
1051 return;
1052 luaL_unref(gL.T, LUA_REGISTRYINDEX, lua->Tref);
1053 RESET_SAFE_LJMP(gL.T);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001054 /* Forces a garbage collecting process. If the Lua program is finished
1055 * without error, we run the GC on the thread pointer. Its freed all
1056 * the unused memory.
1057 * If the thread is finnish with an error or is currently yielded,
1058 * it seems that the GC applied on the thread doesn't clean anything,
1059 * so e run the GC on the main thread.
1060 * NOTE: maybe this action locks all the Lua threads untiml the en of
1061 * the garbage collection.
1062 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001063 if (lua->gc_count) {
Thierry FOURNIER7bd10d52017-07-17 00:44:40 +02001064 if (!SET_SAFE_LJMP(gL.T))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001065 return;
Thierry FOURNIER7bd10d52017-07-17 00:44:40 +02001066 lua_gc(gL.T, LUA_GCCOLLECT, 0);
1067 RESET_SAFE_LJMP(gL.T);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001068 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001069
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001070 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001071
1072end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001073 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001074}
1075
1076/* This function is used to restore the Lua context when a coroutine
1077 * fails. This function copy the common memory between old coroutine
1078 * and the new coroutine. The old coroutine is destroyed, and its
1079 * replaced by the new coroutine.
1080 * If the flag "keep_msg" is set, the last entry of the old is assumed
1081 * as string error message and it is copied in the new stack.
1082 */
1083static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1084{
1085 lua_State *T;
1086 int new_ref;
1087
1088 /* Renew the main LUA stack doesn't have sense. */
1089 if (lua == &gL)
1090 return 0;
1091
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001092 /* New Lua coroutine. */
1093 T = lua_newthread(gL.T);
1094 if (!T)
1095 return 0;
1096
1097 /* Copy last error message. */
1098 if (keep_msg)
1099 lua_xmove(lua->T, T, 1);
1100
1101 /* Copy data between the coroutines. */
1102 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1103 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001104 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001105
1106 /* Destroy old data. */
1107 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1108
1109 /* The thread is garbage collected by Lua. */
1110 luaL_unref(gL.T, LUA_REGISTRYINDEX, lua->Tref);
1111
1112 /* Fill the struct with the new coroutine values. */
1113 lua->Mref = new_ref;
1114 lua->T = T;
1115 lua->Tref = luaL_ref(gL.T, LUA_REGISTRYINDEX);
1116
1117 /* Set context. */
1118 hlua_sethlua(lua);
1119
1120 return 1;
1121}
1122
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001123void hlua_hook(lua_State *L, lua_Debug *ar)
1124{
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001125 struct hlua *hlua = hlua_gethlua(L);
1126
1127 /* Lua cannot yield when its returning from a function,
1128 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001129 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001130 */
1131 if (lua_gethookmask(L) & LUA_MASKRET) {
1132 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1133 return;
1134 }
1135
1136 /* restore the interrupt condition. */
1137 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1138
1139 /* If we interrupt the Lua processing in yieldable state, we yield.
1140 * If the state is not yieldable, trying yield causes an error.
1141 */
1142 if (lua_isyieldable(L))
Willy Tarreau9635e032018-10-16 17:52:55 +02001143 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001144
Thierry FOURNIERa85cfb12015-03-13 14:50:06 +01001145 /* If we cannot yield, update the clock and check the timeout. */
1146 tv_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001147 hlua->run_time += now_ms - hlua->start_time;
1148 if (hlua->max_time && hlua->run_time >= hlua->max_time) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001149 lua_pushfstring(L, "execution timeout");
1150 WILL_LJMP(lua_error(L));
1151 }
1152
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001153 /* Update the start time. */
1154 hlua->start_time = now_ms;
1155
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001156 /* Try to interrupt the process at the end of the current
1157 * unyieldable function.
1158 */
1159 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001160}
1161
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001162/* This function start or resumes the Lua stack execution. If the flag
1163 * "yield_allowed" if no set and the LUA stack execution returns a yield
1164 * The function return an error.
1165 *
1166 * The function can returns 4 values:
1167 * - HLUA_E_OK : The execution is terminated without any errors.
1168 * - HLUA_E_AGAIN : The execution must continue at the next associated
1169 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001170 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001171 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001172 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001173 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001174 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001175 * LUA code.
1176 */
1177static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1178{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001179#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1180 int nres;
1181#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001182 int ret;
1183 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001184 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001185
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001186 /* Initialise run time counter. */
1187 if (!HLUA_IS_RUNNING(lua))
1188 lua->run_time = 0;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001189
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001190 /* Lock the whole Lua execution. This lock must be before the
1191 * label "resume_execution".
1192 */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001193 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001194
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001195resume_execution:
1196
1197 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1198 * instructions. it is used for preventing infinite loops.
1199 */
1200 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1201
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001202 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001203 HLUA_SET_RUN(lua);
1204 HLUA_CLR_CTRLYIELD(lua);
1205 HLUA_CLR_WAKERESWR(lua);
1206 HLUA_CLR_WAKEREQWR(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001207
Christopher Fauletbc275a92020-02-26 14:55:16 +01001208 /* Update the start time and reset wake_time. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001209 lua->start_time = now_ms;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001210 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001211
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001212 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001213#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1214 ret = lua_resume(lua->T, gL.T, lua->nargs, &nres);
1215#else
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001216 ret = lua_resume(lua->T, gL.T, lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001217#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001218 switch (ret) {
1219
1220 case LUA_OK:
1221 ret = HLUA_E_OK;
1222 break;
1223
1224 case LUA_YIELD:
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001225 /* Check if the execution timeout is expired. It it is the case, we
1226 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001227 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001228 tv_update_date(0, 1);
1229 lua->run_time += now_ms - lua->start_time;
1230 if (lua->max_time && lua->run_time > lua->max_time) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001231 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001232 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001233 break;
1234 }
1235 /* Process the forced yield. if the general yield is not allowed or
1236 * if no task were associated this the current Lua execution
1237 * coroutine, we resume the execution. Else we want to return in the
1238 * scheduler and we want to be waked up again, to continue the
1239 * current Lua execution. So we schedule our own task.
1240 */
1241 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001242 if (!yield_allowed || !lua->task)
1243 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001244 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001245 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001246 if (!yield_allowed) {
1247 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001248 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001249 break;
1250 }
1251 ret = HLUA_E_AGAIN;
1252 break;
1253
1254 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001255
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001256 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001257 * because the errors ares the only one mean to return immediately
1258 * from and lua execution.
1259 */
1260 if (lua->flags & HLUA_EXIT) {
1261 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001262 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001263 break;
1264 }
1265
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001266 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001267 if (!lua_checkstack(lua->T, 1)) {
1268 ret = HLUA_E_ERR;
1269 break;
1270 }
1271 msg = lua_tostring(lua->T, -1);
1272 lua_settop(lua->T, 0); /* Empty the stack. */
1273 lua_pop(lua->T, 1);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001274 trace = hlua_traceback(lua->T);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001275 if (msg)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001276 lua_pushfstring(lua->T, "runtime error: %s from %s", msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001277 else
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001278 lua_pushfstring(lua->T, "unknown runtime error from %s", trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001279 ret = HLUA_E_ERRMSG;
1280 break;
1281
1282 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001283 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001284 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001285 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001286 break;
1287
1288 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001289 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001290 if (!lua_checkstack(lua->T, 1)) {
1291 ret = HLUA_E_ERR;
1292 break;
1293 }
1294 msg = lua_tostring(lua->T, -1);
1295 lua_settop(lua->T, 0); /* Empty the stack. */
1296 lua_pop(lua->T, 1);
1297 if (msg)
1298 lua_pushfstring(lua->T, "message handler error: %s", msg);
1299 else
1300 lua_pushfstring(lua->T, "message handler error");
1301 ret = HLUA_E_ERRMSG;
1302 break;
1303
1304 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001305 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001306 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001307 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001308 break;
1309 }
1310
1311 switch (ret) {
1312 case HLUA_E_AGAIN:
1313 break;
1314
1315 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001316 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001317 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001318 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001319 break;
1320
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001321 case HLUA_E_ETMOUT:
1322 case HLUA_E_NOMEM:
1323 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001324 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001325 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001326 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001327 hlua_ctx_renew(lua, 0);
1328 break;
1329
1330 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001331 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001332 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001333 break;
1334 }
1335
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001336 /* This is the main exit point, remove the Lua lock. */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001337 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001338
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001339 return ret;
1340}
1341
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001342/* This function exit the current code. */
1343__LJMP static int hlua_done(lua_State *L)
1344{
1345 struct hlua *hlua = hlua_gethlua(L);
1346
1347 hlua->flags |= HLUA_EXIT;
1348 WILL_LJMP(lua_error(L));
1349
1350 return 0;
1351}
1352
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001353/* This function is an LUA binding. It provides a function
1354 * for deleting ACL from a referenced ACL file.
1355 */
1356__LJMP static int hlua_del_acl(lua_State *L)
1357{
1358 const char *name;
1359 const char *key;
1360 struct pat_ref *ref;
1361
1362 MAY_LJMP(check_args(L, 2, "del_acl"));
1363
1364 name = MAY_LJMP(luaL_checkstring(L, 1));
1365 key = MAY_LJMP(luaL_checkstring(L, 2));
1366
1367 ref = pat_ref_lookup(name);
1368 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001369 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001370
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001371 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001372 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001373 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001374 return 0;
1375}
1376
1377/* This function is an LUA binding. It provides a function
1378 * for deleting map entry from a referenced map file.
1379 */
1380static int hlua_del_map(lua_State *L)
1381{
1382 const char *name;
1383 const char *key;
1384 struct pat_ref *ref;
1385
1386 MAY_LJMP(check_args(L, 2, "del_map"));
1387
1388 name = MAY_LJMP(luaL_checkstring(L, 1));
1389 key = MAY_LJMP(luaL_checkstring(L, 2));
1390
1391 ref = pat_ref_lookup(name);
1392 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001393 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001394
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001395 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001396 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001397 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001398 return 0;
1399}
1400
1401/* This function is an LUA binding. It provides a function
1402 * for adding ACL pattern from a referenced ACL file.
1403 */
1404static int hlua_add_acl(lua_State *L)
1405{
1406 const char *name;
1407 const char *key;
1408 struct pat_ref *ref;
1409
1410 MAY_LJMP(check_args(L, 2, "add_acl"));
1411
1412 name = MAY_LJMP(luaL_checkstring(L, 1));
1413 key = MAY_LJMP(luaL_checkstring(L, 2));
1414
1415 ref = pat_ref_lookup(name);
1416 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001417 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001418
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001419 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001420 if (pat_ref_find_elt(ref, key) == NULL)
1421 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001422 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001423 return 0;
1424}
1425
1426/* This function is an LUA binding. It provides a function
1427 * for setting map pattern and sample from a referenced map
1428 * file.
1429 */
1430static int hlua_set_map(lua_State *L)
1431{
1432 const char *name;
1433 const char *key;
1434 const char *value;
1435 struct pat_ref *ref;
1436
1437 MAY_LJMP(check_args(L, 3, "set_map"));
1438
1439 name = MAY_LJMP(luaL_checkstring(L, 1));
1440 key = MAY_LJMP(luaL_checkstring(L, 2));
1441 value = MAY_LJMP(luaL_checkstring(L, 3));
1442
1443 ref = pat_ref_lookup(name);
1444 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001445 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001446
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001447 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001448 if (pat_ref_find_elt(ref, key) != NULL)
1449 pat_ref_set(ref, key, value, NULL);
1450 else
1451 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001452 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001453 return 0;
1454}
1455
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001456/* A class is a lot of memory that contain data. This data can be a table,
1457 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001458 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001459 * the name of the object (_G[<name>] = <metable> ).
1460 *
1461 * A metable is a table that modify the standard behavior of a standard
1462 * access to the associated data. The entries of this new metatable are
1463 * defined as is:
1464 *
1465 * http://lua-users.org/wiki/MetatableEvents
1466 *
1467 * __index
1468 *
1469 * we access an absent field in a table, the result is nil. This is
1470 * true, but it is not the whole truth. Actually, such access triggers
1471 * the interpreter to look for an __index metamethod: If there is no
1472 * such method, as usually happens, then the access results in nil;
1473 * otherwise, the metamethod will provide the result.
1474 *
1475 * Control 'prototype' inheritance. When accessing "myTable[key]" and
1476 * the key does not appear in the table, but the metatable has an __index
1477 * property:
1478 *
1479 * - if the value is a function, the function is called, passing in the
1480 * table and the key; the return value of that function is returned as
1481 * the result.
1482 *
1483 * - if the value is another table, the value of the key in that table is
1484 * asked for and returned (and if it doesn't exist in that table, but that
1485 * table's metatable has an __index property, then it continues on up)
1486 *
1487 * - Use "rawget(myTable,key)" to skip this metamethod.
1488 *
1489 * http://www.lua.org/pil/13.4.1.html
1490 *
1491 * __newindex
1492 *
1493 * Like __index, but control property assignment.
1494 *
1495 * __mode - Control weak references. A string value with one or both
1496 * of the characters 'k' and 'v' which specifies that the the
1497 * keys and/or values in the table are weak references.
1498 *
1499 * __call - Treat a table like a function. When a table is followed by
1500 * parenthesis such as "myTable( 'foo' )" and the metatable has
1501 * a __call key pointing to a function, that function is invoked
1502 * (passing any specified arguments) and the return value is
1503 * returned.
1504 *
1505 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
1506 * called, if the metatable for myTable has a __metatable
1507 * key, the value of that key is returned instead of the
1508 * actual metatable.
1509 *
1510 * __tostring - Control string representation. When the builtin
1511 * "tostring( myTable )" function is called, if the metatable
1512 * for myTable has a __tostring property set to a function,
1513 * that function is invoked (passing myTable to it) and the
1514 * return value is used as the string representation.
1515 *
1516 * __len - Control table length. When the table length is requested using
1517 * the length operator ( '#' ), if the metatable for myTable has
1518 * a __len key pointing to a function, that function is invoked
1519 * (passing myTable to it) and the return value used as the value
1520 * of "#myTable".
1521 *
1522 * __gc - Userdata finalizer code. When userdata is set to be garbage
1523 * collected, if the metatable has a __gc field pointing to a
1524 * function, that function is first invoked, passing the userdata
1525 * to it. The __gc metamethod is not called for tables.
1526 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
1527 *
1528 * Special metamethods for redefining standard operators:
1529 * http://www.lua.org/pil/13.1.html
1530 *
1531 * __add "+"
1532 * __sub "-"
1533 * __mul "*"
1534 * __div "/"
1535 * __unm "!"
1536 * __pow "^"
1537 * __concat ".."
1538 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001539 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001540 * http://www.lua.org/pil/13.2.html
1541 *
1542 * __eq "=="
1543 * __lt "<"
1544 * __le "<="
1545 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001546
1547/*
1548 *
1549 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001550 * Class Map
1551 *
1552 *
1553 */
1554
1555/* Returns a struct hlua_map if the stack entry "ud" is
1556 * a class session, otherwise it throws an error.
1557 */
1558__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
1559{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001560 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001561}
1562
1563/* This function is the map constructor. It don't need
1564 * the class Map object. It creates and return a new Map
1565 * object. It must be called only during "body" or "init"
1566 * context because it process some filesystem accesses.
1567 */
1568__LJMP static int hlua_map_new(struct lua_State *L)
1569{
1570 const char *fn;
1571 int match = PAT_MATCH_STR;
1572 struct sample_conv conv;
1573 const char *file = "";
1574 int line = 0;
1575 lua_Debug ar;
1576 char *err = NULL;
1577 struct arg args[2];
1578
1579 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
1580 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
1581
1582 fn = MAY_LJMP(luaL_checkstring(L, 1));
1583
1584 if (lua_gettop(L) >= 2) {
1585 match = MAY_LJMP(luaL_checkinteger(L, 2));
1586 if (match < 0 || match >= PAT_MATCH_NUM)
1587 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
1588 }
1589
1590 /* Get Lua filename and line number. */
1591 if (lua_getstack(L, 1, &ar)) { /* check function at level */
1592 lua_getinfo(L, "Sl", &ar); /* get info about it */
1593 if (ar.currentline > 0) { /* is there info? */
1594 file = ar.short_src;
1595 line = ar.currentline;
1596 }
1597 }
1598
1599 /* fill fake sample_conv struct. */
1600 conv.kw = ""; /* unused. */
1601 conv.process = NULL; /* unused. */
1602 conv.arg_mask = 0; /* unused. */
1603 conv.val_args = NULL; /* unused. */
1604 conv.out_type = SMP_T_STR;
1605 conv.private = (void *)(long)match;
1606 switch (match) {
1607 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
1608 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
1609 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
1610 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
1611 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
1612 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
1613 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001614 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001615 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
1616 default:
1617 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
1618 }
1619
1620 /* fill fake args. */
1621 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02001622 args[0].data.str.area = strdup(fn);
1623 args[0].data.str.data = strlen(fn);
1624 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001625 args[1].type = ARGT_STOP;
1626
1627 /* load the map. */
1628 if (!sample_load_map(args, &conv, file, line, &err)) {
1629 /* error case: we cant use luaL_error because we must
1630 * free the err variable.
1631 */
1632 luaL_where(L, 1);
1633 lua_pushfstring(L, "'new': %s.", err);
1634 lua_concat(L, 2);
1635 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001636 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001637 WILL_LJMP(lua_error(L));
1638 }
1639
1640 /* create the lua object. */
1641 lua_newtable(L);
1642 lua_pushlightuserdata(L, args[0].data.map);
1643 lua_rawseti(L, -2, 0);
1644
1645 /* Pop a class Map metatable and affect it to the userdata. */
1646 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
1647 lua_setmetatable(L, -2);
1648
1649
1650 return 1;
1651}
1652
1653__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
1654{
1655 struct map_descriptor *desc;
1656 struct pattern *pat;
1657 struct sample smp;
1658
1659 MAY_LJMP(check_args(L, 2, "lookup"));
1660 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001661 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001662 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001663 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001664 }
1665 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001666 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001667 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001668 smp.data.u.str.area = (char *)MAY_LJMP(luaL_checklstring(L, 2, (size_t *)&smp.data.u.str.data));
Thierry Fournier66e9ff52020-11-10 20:38:20 +01001669 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001670 }
1671
1672 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02001673 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001674 if (str)
1675 lua_pushstring(L, "");
1676 else
1677 lua_pushnil(L);
1678 return 1;
1679 }
1680
1681 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001682 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001683 return 1;
1684}
1685
1686__LJMP static int hlua_map_lookup(struct lua_State *L)
1687{
1688 return _hlua_map_lookup(L, 0);
1689}
1690
1691__LJMP static int hlua_map_slookup(struct lua_State *L)
1692{
1693 return _hlua_map_lookup(L, 1);
1694}
1695
1696/*
1697 *
1698 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001699 * Class Socket
1700 *
1701 *
1702 */
1703
1704__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
1705{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001706 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001707}
1708
1709/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001710 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001711 * received.
1712 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001713static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001714{
Willy Tarreau00a37f02015-04-13 12:05:19 +02001715 struct stream_interface *si = appctx->owner;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001716
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001717 if (appctx->ctx.hlua_cosocket.die) {
1718 si_shutw(si);
1719 si_shutr(si);
1720 si_ic(si)->flags |= CF_READ_NULL;
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001721 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1722 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001723 stream_shutdown(si_strm(si), SF_ERR_KILLED);
1724 }
1725
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001726 /* If we cant write, wakeup the pending write signals. */
1727 if (channel_output_closed(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001728 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001729
1730 /* If we cant read, wakeup the pending read signals. */
1731 if (channel_input_closed(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001732 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001733
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001734 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001735 * to be notified whenever the connection completes.
1736 */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001737 if (si_opposite(si)->state < SI_ST_EST) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01001738 si_cant_get(si);
Willy Tarreau12c24232018-12-06 15:29:50 +01001739 si_rx_conn_blk(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01001740 si_rx_endp_more(si);
Willy Tarreaud4da1962015-04-20 01:31:23 +02001741 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001742 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001743
1744 /* This function is called after the connect. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01001745 appctx->ctx.hlua_cosocket.connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001746
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001747 /* Wake the tasks which wants to write if the buffer have available space. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001748 if (channel_may_recv(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001749 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001750
1751 /* Wake the tasks which wants to read if the buffer contains data. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001752 if (!channel_is_empty(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001753 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001754
1755 /* Some data were injected in the buffer, notify the stream
1756 * interface.
1757 */
1758 if (!channel_is_empty(si_ic(si)))
Willy Tarreau14bfe9a2018-12-19 15:19:27 +01001759 si_update(si);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001760
1761 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01001762 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001763 */
1764 if (notification_registered(&appctx->ctx.hlua_cosocket.wake_on_write))
Willy Tarreau3367d412018-11-15 10:57:41 +01001765 si_rx_endp_more(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001766}
1767
Willy Tarreau87b09662015-04-03 00:22:06 +02001768/* This function is called when the "struct stream" is destroyed.
1769 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001770 * Wake all the pending signals.
1771 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001772static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001773{
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001774 struct xref *peer;
1775
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001776 /* Remove my link in the original object. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001777 peer = xref_get_peer_and_lock(&appctx->ctx.hlua_cosocket.xref);
1778 if (peer)
1779 xref_disconnect(&appctx->ctx.hlua_cosocket.xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001780
1781 /* Wake all the task waiting for me. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001782 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1783 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001784}
1785
1786/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02001787 * uses this object. If the stream does not exists, just quit.
1788 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001789 * pending signal can rest in the read and write lists. destroy
1790 * it.
1791 */
1792__LJMP static int hlua_socket_gc(lua_State *L)
1793{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001794 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001795 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001796 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001797
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001798 MAY_LJMP(check_args(L, 1, "__gc"));
1799
1800 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001801 peer = xref_get_peer_and_lock(&socket->xref);
1802 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001803 return 0;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001804 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001805
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001806 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001807 appctx->ctx.hlua_cosocket.die = 1;
1808 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001809
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001810 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001811 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001812 return 0;
1813}
1814
1815/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02001816 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001817 */
sada05ed3302018-05-11 11:48:18 -07001818__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001819{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001820 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001821 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001822 struct xref *peer;
Willy Tarreauf31af932020-01-14 09:59:38 +01001823 struct hlua *hlua = hlua_gethlua(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001824
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001825 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02001826
1827 /* Check if we run on the same thread than the xreator thread.
1828 * We cannot access to the socket if the thread is different.
1829 */
1830 if (socket->tid != tid)
1831 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
1832
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001833 peer = xref_get_peer_and_lock(&socket->xref);
1834 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001835 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001836
1837 hlua->gc_count--;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001838 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001839
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001840 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001841 appctx->ctx.hlua_cosocket.die = 1;
1842 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001843
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001844 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001845 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001846 return 0;
1847}
1848
sada05ed3302018-05-11 11:48:18 -07001849/* The close function calls close_helper.
1850 */
1851__LJMP static int hlua_socket_close(lua_State *L)
1852{
1853 MAY_LJMP(check_args(L, 1, "close"));
1854 return hlua_socket_close_helper(L);
1855}
1856
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001857/* This Lua function assumes that the stack contain three parameters.
1858 * 1 - USERDATA containing a struct socket
1859 * 2 - INTEGER with values of the macro defined below
1860 * If the integer is -1, we must read at most one line.
1861 * If the integer is -2, we ust read all the data until the
1862 * end of the stream.
1863 * If the integer is positive value, we must read a number of
1864 * bytes corresponding to this value.
1865 */
1866#define HLSR_READ_LINE (-1)
1867#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001868__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001869{
1870 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
1871 int wanted = lua_tointeger(L, 2);
1872 struct hlua *hlua = hlua_gethlua(L);
1873 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001874 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001875 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02001876 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001877 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02001878 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001879 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01001880 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01001881 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001882 struct stream_interface *si;
1883 struct stream *s;
1884 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02001885 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001886
1887 /* Check if this lua stack is schedulable. */
1888 if (!hlua || !hlua->task)
1889 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
1890 "'frontend', 'backend' or 'task'"));
1891
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02001892 /* Check if we run on the same thread than the xreator thread.
1893 * We cannot access to the socket if the thread is different.
1894 */
1895 if (socket->tid != tid)
1896 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
1897
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001898 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001899 peer = xref_get_peer_and_lock(&socket->xref);
1900 if (!peer)
1901 goto no_peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001902 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
1903 si = appctx->owner;
1904 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001905
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001906 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001907 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001908 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02001909 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001910 if (nblk < 0) /* Connection close. */
1911 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001912 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001913 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01001914
1915 /* remove final \r\n. */
1916 if (nblk == 1) {
1917 if (blk1[len1-1] == '\n') {
1918 len1--;
1919 skip_at_end++;
1920 if (blk1[len1-1] == '\r') {
1921 len1--;
1922 skip_at_end++;
1923 }
1924 }
1925 }
1926 else {
1927 if (blk2[len2-1] == '\n') {
1928 len2--;
1929 skip_at_end++;
1930 if (blk2[len2-1] == '\r') {
1931 len2--;
1932 skip_at_end++;
1933 }
1934 }
1935 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001936 }
1937
1938 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001939 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02001940 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001941 if (nblk < 0) /* Connection close. */
1942 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001943 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001944 goto connection_empty;
1945 }
1946
1947 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001948 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02001949 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001950 if (nblk < 0) /* Connection close. */
1951 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001952 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001953 goto connection_empty;
1954
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02001955 missing_bytes = wanted - socket->b.n;
1956 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001957 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02001958 len1 = missing_bytes;
1959 } if (nblk == 2 && len1 + len2 > missing_bytes)
1960 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001961 }
1962
1963 len = len1;
1964
1965 luaL_addlstring(&socket->b, blk1, len1);
1966 if (nblk == 2) {
1967 len += len2;
1968 luaL_addlstring(&socket->b, blk2, len2);
1969 }
1970
1971 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02001972 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001973
1974 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02001975 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001976
1977 /* If the pattern reclaim to read all the data
1978 * in the connection, got out.
1979 */
1980 if (wanted == HLSR_READ_ALL)
1981 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02001982 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001983 goto connection_empty;
1984
1985 /* Return result. */
1986 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001987 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001988 return 1;
1989
1990connection_closed:
1991
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001992 xref_unlock(&socket->xref, peer);
1993
1994no_peer:
1995
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001996 /* If the buffer containds data. */
1997 if (socket->b.n > 0) {
1998 luaL_pushresult(&socket->b);
1999 return 1;
2000 }
2001 lua_pushnil(L);
2002 lua_pushstring(L, "connection closed.");
2003 return 2;
2004
2005connection_empty:
2006
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002007 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_read, hlua->task)) {
2008 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002009 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002010 }
2011 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002012 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002013 return 0;
2014}
2015
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002016/* This Lua function gets two parameters. The first one can be string
2017 * or a number. If the string is "*l", the user requires one line. If
2018 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002019 * If the value is a number, the user require a number of bytes equal
2020 * to the value. The default value is "*l" (a line).
2021 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002022 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002023 * integer takes this values:
2024 * -1 : read a line
2025 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002026 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002027 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002028 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002029 * concatenated with the read data.
2030 */
2031__LJMP static int hlua_socket_receive(struct lua_State *L)
2032{
2033 int wanted = HLSR_READ_LINE;
2034 const char *pattern;
2035 int type;
2036 char *error;
2037 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002038 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002039
2040 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2041 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2042
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002043 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002044
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002045 /* Check if we run on the same thread than the xreator thread.
2046 * We cannot access to the socket if the thread is different.
2047 */
2048 if (socket->tid != tid)
2049 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2050
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002051 /* check for pattern. */
2052 if (lua_gettop(L) >= 2) {
2053 type = lua_type(L, 2);
2054 if (type == LUA_TSTRING) {
2055 pattern = lua_tostring(L, 2);
2056 if (strcmp(pattern, "*a") == 0)
2057 wanted = HLSR_READ_ALL;
2058 else if (strcmp(pattern, "*l") == 0)
2059 wanted = HLSR_READ_LINE;
2060 else {
2061 wanted = strtoll(pattern, &error, 10);
2062 if (*error != '\0')
2063 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2064 }
2065 }
2066 else if (type == LUA_TNUMBER) {
2067 wanted = lua_tointeger(L, 2);
2068 if (wanted < 0)
2069 WILL_LJMP(luaL_error(L, "Unsupported size."));
2070 }
2071 }
2072
2073 /* Set pattern. */
2074 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002075
2076 /* Check if we would replace the top by itself. */
2077 if (lua_gettop(L) != 2)
2078 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002079
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002080 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002081 luaL_buffinit(L, &socket->b);
2082
2083 /* Check prefix. */
2084 if (lua_gettop(L) >= 3) {
2085 if (lua_type(L, 3) != LUA_TSTRING)
2086 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2087 pattern = lua_tolstring(L, 3, &len);
2088 luaL_addlstring(&socket->b, pattern, len);
2089 }
2090
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002091 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002092}
2093
2094/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002095 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002096 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002097static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002098{
2099 struct hlua_socket *socket;
2100 struct hlua *hlua = hlua_gethlua(L);
2101 struct appctx *appctx;
2102 size_t buf_len;
2103 const char *buf;
2104 int len;
2105 int send_len;
2106 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002107 struct xref *peer;
2108 struct stream_interface *si;
2109 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002110
2111 /* Check if this lua stack is schedulable. */
2112 if (!hlua || !hlua->task)
2113 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2114 "'frontend', 'backend' or 'task'"));
2115
2116 /* Get object */
2117 socket = MAY_LJMP(hlua_checksocket(L, 1));
2118 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002119 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002120
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002121 /* Check if we run on the same thread than the xreator thread.
2122 * We cannot access to the socket if the thread is different.
2123 */
2124 if (socket->tid != tid)
2125 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2126
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002127 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002128 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002129 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002130 lua_pushinteger(L, -1);
2131 return 1;
2132 }
2133 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2134 si = appctx->owner;
2135 s = si_strm(si);
2136
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002137 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002138 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002139 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002140 lua_pushinteger(L, -1);
2141 return 1;
2142 }
2143
2144 /* Update the input buffer data. */
2145 buf += sent;
2146 send_len = buf_len - sent;
2147
2148 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002149 if (sent >= buf_len) {
2150 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002151 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002152 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002153
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002154 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002155 * the request buffer if its not required.
2156 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002157 if (s->req.buf.size == 0) {
Willy Tarreau581abd32018-10-25 10:21:41 +02002158 if (!si_alloc_ibuf(si, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002159 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002160 }
2161
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002162 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002163 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002164 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002165 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002166 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002167
2168 /* send data */
2169 if (len < send_len)
2170 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002171 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002172
2173 /* "Not enough space" (-1), "Buffer too little to contain
2174 * the data" (-2) are not expected because the available length
2175 * is tested.
2176 * Other unknown error are also not expected.
2177 */
2178 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002179 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002180 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002181
sada05ed3302018-05-11 11:48:18 -07002182 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002183 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002184 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002185 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002186 return 1;
2187 }
2188
2189 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002190 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002191
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002192 s->req.rex = TICK_ETERNITY;
2193 s->res.wex = TICK_ETERNITY;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002194
2195 /* Update length sent. */
2196 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002197 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002198
2199 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002200 if (sent + len >= buf_len) {
2201 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002202 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002203 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002204
2205hlua_socket_write_yield_return:
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002206 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2207 xref_unlock(&socket->xref, peer);
2208 WILL_LJMP(luaL_error(L, "out of memory"));
2209 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002210 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002211 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002212 return 0;
2213}
2214
2215/* This function initiate the send of data. It just check the input
2216 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002217 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002218 * "hlua_socket_write_yield" that can yield.
2219 *
2220 * The Lua function gets between 3 and 4 parameters. The first one is
2221 * the associated object. The second is a string buffer. The third is
2222 * a facultative integer that represents where is the buffer position
2223 * of the start of the data that can send. The first byte is the
2224 * position "1". The default value is "1". The fourth argument is a
2225 * facultative integer that represents where is the buffer position
2226 * of the end of the data that can send. The default is the last byte.
2227 */
2228static int hlua_socket_send(struct lua_State *L)
2229{
2230 int i;
2231 int j;
2232 const char *buf;
2233 size_t buf_len;
2234
2235 /* Check number of arguments. */
2236 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2237 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2238
2239 /* Get the string. */
2240 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2241
2242 /* Get and check j. */
2243 if (lua_gettop(L) == 4) {
2244 j = MAY_LJMP(luaL_checkinteger(L, 4));
2245 if (j < 0)
2246 j = buf_len + j + 1;
2247 if (j > buf_len)
2248 j = buf_len + 1;
2249 lua_pop(L, 1);
2250 }
2251 else
2252 j = buf_len;
2253
2254 /* Get and check i. */
2255 if (lua_gettop(L) == 3) {
2256 i = MAY_LJMP(luaL_checkinteger(L, 3));
2257 if (i < 0)
2258 i = buf_len + i + 1;
2259 if (i > buf_len)
2260 i = buf_len + 1;
2261 lua_pop(L, 1);
2262 } else
2263 i = 1;
2264
2265 /* Check bth i and j. */
2266 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002267 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002268 return 1;
2269 }
2270 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002271 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002272 return 1;
2273 }
2274 if (i == 0)
2275 i = 1;
2276 if (j == 0)
2277 j = 1;
2278
2279 /* Pop the string. */
2280 lua_pop(L, 1);
2281
2282 /* Update the buffer length. */
2283 buf += i - 1;
2284 buf_len = j - i + 1;
2285 lua_pushlstring(L, buf, buf_len);
2286
2287 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002288 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002289
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002290 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002291}
2292
Willy Tarreau22b0a682015-06-17 19:43:49 +02002293#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002294__LJMP static inline int hlua_socket_info(struct lua_State *L, struct sockaddr_storage *addr)
2295{
2296 static char buffer[SOCKET_INFO_MAX_LEN];
2297 int ret;
2298 int len;
2299 char *p;
2300
2301 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2302 if (ret <= 0) {
2303 lua_pushnil(L);
2304 return 1;
2305 }
2306
2307 if (ret == AF_UNIX) {
2308 lua_pushstring(L, buffer+1);
2309 return 1;
2310 }
2311 else if (ret == AF_INET6) {
2312 buffer[0] = '[';
2313 len = strlen(buffer);
2314 buffer[len] = ']';
2315 len++;
2316 buffer[len] = ':';
2317 len++;
2318 p = buffer;
2319 }
2320 else if (ret == AF_INET) {
2321 p = buffer + 1;
2322 len = strlen(p);
2323 p[len] = ':';
2324 len++;
2325 }
2326 else {
2327 lua_pushnil(L);
2328 return 1;
2329 }
2330
2331 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2332 lua_pushnil(L);
2333 return 1;
2334 }
2335
2336 lua_pushstring(L, p);
2337 return 1;
2338}
2339
2340/* Returns information about the peer of the connection. */
2341__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2342{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002343 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002344 struct xref *peer;
2345 struct appctx *appctx;
2346 struct stream_interface *si;
2347 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002348 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002349
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002350 MAY_LJMP(check_args(L, 1, "getpeername"));
2351
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002352 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002353
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002354 /* Check if we run on the same thread than the xreator thread.
2355 * We cannot access to the socket if the thread is different.
2356 */
2357 if (socket->tid != tid)
2358 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2359
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002360 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002361 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002362 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002363 lua_pushnil(L);
2364 return 1;
2365 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002366 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2367 si = appctx->owner;
2368 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002369
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002370 if (!s->target_addr) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002371 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002372 lua_pushnil(L);
2373 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002374 }
2375
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002376 ret = MAY_LJMP(hlua_socket_info(L, s->target_addr));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002377 xref_unlock(&socket->xref, peer);
2378 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002379}
2380
2381/* Returns information about my connection side. */
2382static int hlua_socket_getsockname(struct lua_State *L)
2383{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002384 struct hlua_socket *socket;
2385 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002386 struct appctx *appctx;
2387 struct xref *peer;
2388 struct stream_interface *si;
2389 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002390 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002391
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002392 MAY_LJMP(check_args(L, 1, "getsockname"));
2393
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002394 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002395
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002396 /* Check if we run on the same thread than the xreator thread.
2397 * We cannot access to the socket if the thread is different.
2398 */
2399 if (socket->tid != tid)
2400 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2401
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002402 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002403 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002404 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002405 lua_pushnil(L);
2406 return 1;
2407 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002408 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2409 si = appctx->owner;
2410 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002411
Olivier Houchard9aaf7782017-09-13 18:30:23 +02002412 conn = cs_conn(objt_cs(s->si[1].end));
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002413 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002414 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002415 lua_pushnil(L);
2416 return 1;
2417 }
2418
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002419 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002420 xref_unlock(&socket->xref, peer);
2421 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002422}
2423
2424/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002425static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002426 .obj_type = OBJ_TYPE_APPLET,
2427 .name = "<LUA_TCP>",
2428 .fct = hlua_socket_handler,
2429 .release = hlua_socket_release,
2430};
2431
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002432__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002433{
2434 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
2435 struct hlua *hlua = hlua_gethlua(L);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002436 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002437 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002438 struct stream_interface *si;
2439 struct stream *s;
2440
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002441 /* Check if we run on the same thread than the xreator thread.
2442 * We cannot access to the socket if the thread is different.
2443 */
2444 if (socket->tid != tid)
2445 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2446
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002447 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002448 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002449 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002450 lua_pushnil(L);
2451 lua_pushstring(L, "Can't connect");
2452 return 2;
2453 }
2454 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2455 si = appctx->owner;
2456 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002457
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002458 /* Check if we run on the same thread than the xreator thread.
2459 * We cannot access to the socket if the thread is different.
2460 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002461 if (socket->tid != tid) {
2462 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002463 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002464 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002465
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002466 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002467 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002468 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002469 lua_pushnil(L);
2470 lua_pushstring(L, "Can't connect");
2471 return 2;
2472 }
2473
Willy Tarreaue09101e2018-10-16 17:37:12 +02002474 appctx = __objt_appctx(s->si[0].end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002475
2476 /* Check for connection established. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002477 if (appctx->ctx.hlua_cosocket.connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002478 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002479 lua_pushinteger(L, 1);
2480 return 1;
2481 }
2482
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002483 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2484 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002485 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002486 }
2487 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002488 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002489 return 0;
2490}
2491
2492/* This function fail or initite the connection. */
2493__LJMP static int hlua_socket_connect(struct lua_State *L)
2494{
2495 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002496 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002497 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002498 struct hlua *hlua;
2499 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002500 int low, high;
2501 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002502 struct xref *peer;
2503 struct stream_interface *si;
2504 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002505
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002506 if (lua_gettop(L) < 2)
2507 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002508
2509 /* Get args. */
2510 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002511
2512 /* Check if we run on the same thread than the xreator thread.
2513 * We cannot access to the socket if the thread is different.
2514 */
2515 if (socket->tid != tid)
2516 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2517
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002518 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002519 if (lua_gettop(L) >= 3) {
2520 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002521 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002522
Tim Duesterhus6edab862018-01-06 19:04:45 +01002523 /* Force the ip to end with a colon, to support IPv6 addresses
2524 * that are not enclosed within square brackets.
2525 */
2526 if (port > 0) {
2527 luaL_buffinit(L, &b);
2528 luaL_addstring(&b, ip);
2529 luaL_addchar(&b, ':');
2530 luaL_pushresult(&b);
2531 ip = lua_tolstring(L, lua_gettop(L), NULL);
2532 }
2533 }
2534
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002535 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002536 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002537 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002538 lua_pushnil(L);
2539 return 1;
2540 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002541
2542 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002543 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 +02002544 if (!addr) {
2545 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002546 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002547 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002548
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002549 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002550 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002551 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002552 if (port == -1) {
2553 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002554 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002555 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002556 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2557 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002558 if (port == -1) {
2559 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002560 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002561 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002562 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002563 }
2564 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002565
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002566 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2567 si = appctx->owner;
2568 s = si_strm(si);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002569
Willy Tarreau9b7587a2020-10-15 07:32:10 +02002570 if (!sockaddr_alloc(&s->target_addr, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002571 xref_unlock(&socket->xref, peer);
2572 WILL_LJMP(luaL_error(L, "connect: internal error"));
2573 }
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002574 s->flags |= SF_ADDR_SET;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002575
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002576 hlua = hlua_gethlua(L);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002577
2578 /* inform the stream that we want to be notified whenever the
2579 * connection completes.
2580 */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01002581 si_cant_get(&s->si[0]);
Willy Tarreau3367d412018-11-15 10:57:41 +01002582 si_rx_endp_more(&s->si[0]);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002583 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002584
Willy Tarreauf31af932020-01-14 09:59:38 +01002585 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002586
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002587 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2588 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002589 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002590 }
2591 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002592
2593 task_wakeup(s->task, TASK_WOKEN_INIT);
2594 /* Return yield waiting for connection. */
2595
Willy Tarreau9635e032018-10-16 17:52:55 +02002596 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002597
2598 return 0;
2599}
2600
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002601#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002602__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
2603{
2604 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002605 struct xref *peer;
2606 struct appctx *appctx;
2607 struct stream_interface *si;
2608 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002609
2610 MAY_LJMP(check_args(L, 3, "connect_ssl"));
2611 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002612
2613 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002614 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002615 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002616 lua_pushnil(L);
2617 return 1;
2618 }
2619 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2620 si = appctx->owner;
2621 s = si_strm(si);
2622
2623 s->target = &socket_ssl.obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002624 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002625 return MAY_LJMP(hlua_socket_connect(L));
2626}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002627#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002628
2629__LJMP static int hlua_socket_setoption(struct lua_State *L)
2630{
2631 return 0;
2632}
2633
2634__LJMP static int hlua_socket_settimeout(struct lua_State *L)
2635{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002636 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002637 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02002638 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002639 struct xref *peer;
2640 struct appctx *appctx;
2641 struct stream_interface *si;
2642 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002643
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002644 MAY_LJMP(check_args(L, 2, "settimeout"));
2645
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002646 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02002647
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002648 /* convert the timeout to millis */
2649 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002650
Thierry Fournier17a921b2018-03-08 09:59:02 +01002651 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02002652 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01002653 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
2654
Mark Lakes56cc1252018-03-27 09:48:06 +02002655 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002656 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02002657
2658 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002659 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002660 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02002661
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002662 /* Check if we run on the same thread than the xreator thread.
2663 * We cannot access to the socket if the thread is different.
2664 */
2665 if (socket->tid != tid)
2666 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2667
Mark Lakes56cc1252018-03-27 09:48:06 +02002668 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002669 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002670 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002671 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
2672 WILL_LJMP(lua_error(L));
2673 return 0;
2674 }
2675 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2676 si = appctx->owner;
2677 s = si_strm(si);
2678
Cyril Bonté7bb63452018-08-17 23:51:02 +02002679 s->sess->fe->timeout.connect = tmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002680 s->req.rto = tmout;
2681 s->req.wto = tmout;
2682 s->res.rto = tmout;
2683 s->res.wto = tmout;
Cyril Bonté7bb63452018-08-17 23:51:02 +02002684 s->req.rex = tick_add_ifset(now_ms, tmout);
2685 s->req.wex = tick_add_ifset(now_ms, tmout);
2686 s->res.rex = tick_add_ifset(now_ms, tmout);
2687 s->res.wex = tick_add_ifset(now_ms, tmout);
2688
2689 s->task->expire = tick_add_ifset(now_ms, tmout);
2690 task_queue(s->task);
2691
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002692 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002693
Thierry Fourniere9636f12018-03-08 09:54:32 +01002694 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01002695 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002696}
2697
2698__LJMP static int hlua_socket_new(lua_State *L)
2699{
2700 struct hlua_socket *socket;
2701 struct appctx *appctx;
Willy Tarreau15b5e142015-04-04 14:38:25 +02002702 struct session *sess;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002703 struct stream *strm;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002704
2705 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002706 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002707 hlua_pusherror(L, "socket: full stack");
2708 goto out_fail_conf;
2709 }
2710
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002711 /* Create the object: obj[0] = userdata. */
2712 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002713 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002714 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002715 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002716 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002717
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002718 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01002719 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01002720 hlua_pusherror(L, "socket: uninitialized pools.");
2721 goto out_fail_conf;
2722 }
2723
Willy Tarreau87b09662015-04-03 00:22:06 +02002724 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002725 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
2726 lua_setmetatable(L, -2);
2727
Willy Tarreaud420a972015-04-06 00:39:18 +02002728 /* Create the applet context */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01002729 appctx = appctx_new(&update_applet, tid_bit);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002730 if (!appctx) {
2731 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaufeb76402015-04-03 14:10:06 +02002732 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002733 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002734
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002735 appctx->ctx.hlua_cosocket.connected = 0;
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002736 appctx->ctx.hlua_cosocket.die = 0;
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002737 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_write);
2738 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02002739
Willy Tarreaud420a972015-04-06 00:39:18 +02002740 /* Now create a session, task and stream for this applet */
2741 sess = session_new(&socket_proxy, NULL, &appctx->obj_type);
2742 if (!sess) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002743 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002744 goto out_fail_sess;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002745 }
2746
Willy Tarreau87787ac2017-08-28 16:22:54 +02002747 strm = stream_new(sess, &appctx->obj_type);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002748 if (!strm) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002749 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002750 goto out_fail_stream;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002751 }
2752
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002753 /* Initialise cross reference between stream and Lua socket object. */
2754 xref_create(&socket->xref, &appctx->ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002755
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002756 /* Configure "right" stream interface. this "si" is used to connect
2757 * and retrieve data from the server. The connection is initialized
2758 * with the "struct server".
2759 */
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002760 si_set_state(&strm->si[1], SI_ST_ASS);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002761
2762 /* Force destination server. */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002763 strm->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002764 strm->target = &socket_tcp.obj_type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002765
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002766 return 1;
2767
Willy Tarreaud420a972015-04-06 00:39:18 +02002768 out_fail_stream:
Willy Tarreau11c36242015-04-04 15:54:03 +02002769 session_free(sess);
Willy Tarreaud420a972015-04-06 00:39:18 +02002770 out_fail_sess:
2771 appctx_free(appctx);
2772 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002773 WILL_LJMP(lua_error(L));
2774 return 0;
2775}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01002776
2777/*
2778 *
2779 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002780 * Class Channel
2781 *
2782 *
2783 */
2784
2785/* Returns the struct hlua_channel join to the class channel in the
2786 * stack entry "ud" or throws an argument error.
2787 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002788__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002789{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002790 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002791}
2792
Willy Tarreau47860ed2015-03-10 14:07:50 +01002793/* Pushes the channel onto the top of the stack. If the stask does not have a
2794 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002795 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01002796static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002797{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002798 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002799 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002800 return 0;
2801
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002802 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01002803 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002804 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002805
2806 /* Pop a class sesison metatable and affect it to the userdata. */
2807 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
2808 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002809 return 1;
2810}
2811
2812/* Duplicate all the data present in the input channel and put it
2813 * in a string LUA variables. Returns -1 and push a nil value in
2814 * the stack if the channel is closed and all the data are consumed,
2815 * returns 0 if no data are available, otherwise it returns the length
Ilya Shipitsind4259502020-04-08 01:07:56 +05002816 * of the built string.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002817 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002818static inline int _hlua_channel_dup(struct channel *chn, lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002819{
2820 char *blk1;
2821 char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002822 size_t len1;
2823 size_t len2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002824 int ret;
2825 luaL_Buffer b;
2826
Willy Tarreau06d80a92017-10-19 14:32:15 +02002827 ret = ci_getblk_nc(chn, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002828 if (unlikely(ret == 0))
2829 return 0;
2830
2831 if (unlikely(ret < 0)) {
2832 lua_pushnil(L);
2833 return -1;
2834 }
2835
2836 luaL_buffinit(L, &b);
2837 luaL_addlstring(&b, blk1, len1);
2838 if (unlikely(ret == 2))
2839 luaL_addlstring(&b, blk2, len2);
2840 luaL_pushresult(&b);
2841
2842 if (unlikely(ret == 2))
2843 return len1 + len2;
2844 return len1;
2845}
2846
2847/* "_hlua_channel_dup" wrapper. If no data are available, it returns
2848 * a yield. This function keep the data in the buffer.
2849 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002850__LJMP static int hlua_channel_dup_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002851{
Willy Tarreau47860ed2015-03-10 14:07:50 +01002852 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002853
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002854 chn = MAY_LJMP(hlua_checkchannel(L, 1));
2855
Thierry Fournier77016da2020-08-15 14:35:51 +02002856 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
2857 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01002858 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02002859 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01002860
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002861 if (_hlua_channel_dup(chn, L) == 0)
Willy Tarreau9635e032018-10-16 17:52:55 +02002862 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_dup_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002863 return 1;
2864}
2865
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002866/* Check arguments for the function "hlua_channel_dup_yield". */
2867__LJMP static int hlua_channel_dup(lua_State *L)
2868{
2869 MAY_LJMP(check_args(L, 1, "dup"));
2870 MAY_LJMP(hlua_checkchannel(L, 1));
2871 return MAY_LJMP(hlua_channel_dup_yield(L, 0, 0));
2872}
2873
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002874/* "_hlua_channel_dup" wrapper. If no data are available, it returns
2875 * a yield. This function consumes the data in the buffer. It returns
2876 * a string containing the data or a nil pointer if no data are available
2877 * and the channel is closed.
2878 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002879__LJMP static int hlua_channel_get_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002880{
Willy Tarreau47860ed2015-03-10 14:07:50 +01002881 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002882 int ret;
2883
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002884 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002885
Thierry Fournier77016da2020-08-15 14:35:51 +02002886 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
2887 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01002888 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02002889 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01002890
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002891 ret = _hlua_channel_dup(chn, L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002892 if (unlikely(ret == 0))
Willy Tarreau9635e032018-10-16 17:52:55 +02002893 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_yield, TICK_ETERNITY, 0));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002894
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002895 if (unlikely(ret == -1))
2896 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002897
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002898 b_sub(&chn->buf, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002899 return 1;
2900}
2901
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002902/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002903__LJMP static int hlua_channel_get(lua_State *L)
2904{
2905 MAY_LJMP(check_args(L, 1, "get"));
2906 MAY_LJMP(hlua_checkchannel(L, 1));
2907 return MAY_LJMP(hlua_channel_get_yield(L, 0, 0));
2908}
2909
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002910/* This functions consumes and returns one line. If the channel is closed,
2911 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002912 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002913 * value.
2914 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002915__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002916{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002917 char *blk1;
2918 char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002919 size_t len1;
2920 size_t len2;
2921 size_t len;
Willy Tarreau47860ed2015-03-10 14:07:50 +01002922 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002923 int ret;
2924 luaL_Buffer b;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002925
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002926 chn = MAY_LJMP(hlua_checkchannel(L, 1));
2927
Thierry Fournier77016da2020-08-15 14:35:51 +02002928 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
2929 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01002930 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02002931 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01002932
Willy Tarreau06d80a92017-10-19 14:32:15 +02002933 ret = ci_getline_nc(chn, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002934 if (ret == 0)
Willy Tarreau9635e032018-10-16 17:52:55 +02002935 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002936
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002937 if (ret == -1) {
2938 lua_pushnil(L);
2939 return 1;
2940 }
2941
2942 luaL_buffinit(L, &b);
2943 luaL_addlstring(&b, blk1, len1);
2944 len = len1;
2945 if (unlikely(ret == 2)) {
2946 luaL_addlstring(&b, blk2, len2);
2947 len += len2;
2948 }
2949 luaL_pushresult(&b);
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002950 b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn) + len, NULL, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002951 return 1;
2952}
2953
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002954/* Check arguments for the function "hlua_channel_getline_yield". */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002955__LJMP static int hlua_channel_getline(lua_State *L)
2956{
2957 MAY_LJMP(check_args(L, 1, "getline"));
2958 MAY_LJMP(hlua_checkchannel(L, 1));
2959 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
2960}
2961
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002962/* This function takes a string as input, and append it at the
2963 * input side of channel. If the data is too big, but a space
2964 * is probably available after sending some data, the function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002965 * yields. If the data is bigger than the buffer, or if the
2966 * channel is closed, it returns -1. Otherwise, it returns the
2967 * amount of data written.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002968 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002969__LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002970{
Willy Tarreau47860ed2015-03-10 14:07:50 +01002971 struct channel *chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002972 size_t len;
2973 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
2974 int l = MAY_LJMP(luaL_checkinteger(L, 3));
2975 int ret;
2976 int max;
2977
Thierry Fournier77016da2020-08-15 14:35:51 +02002978 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
2979 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01002980 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02002981 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01002982
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002983 /* Check if the buffer is available because HAProxy doesn't allocate
Christopher Fauleta73e59b2016-12-09 17:30:18 +01002984 * the request buffer if its not required.
2985 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002986 if (chn->buf.size == 0) {
Willy Tarreau4b962a42018-11-15 11:03:21 +01002987 si_rx_buff_blk(chn_prod(chn));
Willy Tarreau9635e032018-10-16 17:52:55 +02002988 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
Christopher Fauleta73e59b2016-12-09 17:30:18 +01002989 }
2990
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002991 max = channel_recv_limit(chn) - b_data(&chn->buf);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002992 if (max > len - l)
2993 max = len - l;
2994
Willy Tarreau06d80a92017-10-19 14:32:15 +02002995 ret = ci_putblk(chn, str + l, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002996 if (ret == -2 || ret == -3) {
2997 lua_pushinteger(L, -1);
2998 return 1;
2999 }
Willy Tarreaubc18da12015-03-13 14:00:47 +01003000 if (ret == -1) {
3001 chn->flags |= CF_WAKE_WRITE;
Willy Tarreau9635e032018-10-16 17:52:55 +02003002 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
Willy Tarreaubc18da12015-03-13 14:00:47 +01003003 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003004 l += ret;
3005 lua_pop(L, 1);
3006 lua_pushinteger(L, l);
3007
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003008 max = channel_recv_limit(chn) - b_data(&chn->buf);
Willy Tarreaua79021a2018-06-15 18:07:57 +02003009 if (max == 0 && co_data(chn) == 0) {
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003010 /* There are no space available, and the output buffer is empty.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003011 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003012 * we return the amount of copied data.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003013 */
3014 return 1;
3015 }
3016 if (l < len)
Willy Tarreau9635e032018-10-16 17:52:55 +02003017 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003018 return 1;
3019}
3020
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003021/* Just a wrapper of "hlua_channel_append_yield". It returns the length
3022 * of the written string, or -1 if the channel is closed or if the
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003023 * buffer size is too little for the data.
3024 */
3025__LJMP static int hlua_channel_append(lua_State *L)
3026{
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003027 size_t len;
3028
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003029 MAY_LJMP(check_args(L, 2, "append"));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003030 MAY_LJMP(hlua_checkchannel(L, 1));
3031 MAY_LJMP(luaL_checklstring(L, 2, &len));
3032 MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003033 lua_pushinteger(L, 0);
3034
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003035 return MAY_LJMP(hlua_channel_append_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003036}
3037
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003038/* Just a wrapper of "hlua_channel_append_yield". This wrapper starts
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003039 * his process by cleaning the buffer. The result is a replacement
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003040 * of the current data. It returns the length of the written string,
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003041 * or -1 if the channel is closed or if the buffer size is too
3042 * little for the data.
3043 */
3044__LJMP static int hlua_channel_set(lua_State *L)
3045{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003046 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003047
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003048 MAY_LJMP(check_args(L, 2, "set"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003049 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003050 lua_pushinteger(L, 0);
3051
Thierry Fournier77016da2020-08-15 14:35:51 +02003052 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
3053 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003054 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003055 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003056
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003057 b_set_data(&chn->buf, co_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003058
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003059 return MAY_LJMP(hlua_channel_append_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003060}
3061
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003062/* Append data in the output side of the buffer. This data is immediately
3063 * sent. The function returns the amount of data written. If the buffer
3064 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003065 * if the channel is closed.
3066 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003067__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003068{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003069 struct channel *chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003070 size_t len;
3071 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
3072 int l = MAY_LJMP(luaL_checkinteger(L, 3));
3073 int max;
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003074 struct hlua *hlua = hlua_gethlua(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003075
Thierry Fournier77016da2020-08-15 14:35:51 +02003076 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
3077 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003078 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003079 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003080
Willy Tarreau47860ed2015-03-10 14:07:50 +01003081 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003082 lua_pushinteger(L, -1);
3083 return 1;
3084 }
3085
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003086 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003087 * the request buffer if its not required.
3088 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003089 if (chn->buf.size == 0) {
Willy Tarreau4b962a42018-11-15 11:03:21 +01003090 si_rx_buff_blk(chn_prod(chn));
Willy Tarreau9635e032018-10-16 17:52:55 +02003091 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003092 }
3093
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003094 /* The written data will be immediately sent, so we can check
3095 * the available space without taking in account the reserve.
3096 * The reserve is guaranteed for the processing of incoming
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003097 * data, because the buffer will be flushed.
3098 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003099 max = b_room(&chn->buf);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003100
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003101 /* If there is no space available, and the output buffer is empty.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003102 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003103 * we return the amount of copied data.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003104 */
Willy Tarreaua79021a2018-06-15 18:07:57 +02003105 if (max == 0 && co_data(chn) == 0)
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003106 return 1;
3107
3108 /* Adjust the real required length. */
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003109 if (max > len - l)
3110 max = len - l;
3111
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003112 /* The buffer available size may be not contiguous. This test
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003113 * detects a non contiguous buffer and realign it.
3114 */
Willy Tarreau3f679992018-06-15 15:06:42 +02003115 if (ci_space_for_replace(chn) < max)
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003116 channel_slow_realign(chn, trash.area);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003117
3118 /* Copy input data in the buffer. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003119 max = b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn), str + l, max);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003120
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003121 /* buffer replace considers that the input part is filled.
3122 * so, I must forward these new data in the output part.
3123 */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02003124 c_adv(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003125
3126 l += max;
3127 lua_pop(L, 1);
3128 lua_pushinteger(L, l);
3129
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003130 /* If there is no space available, and the output buffer is empty.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003131 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003132 * we return the amount of copied data.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003133 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003134 max = b_room(&chn->buf);
Willy Tarreaua79021a2018-06-15 18:07:57 +02003135 if (max == 0 && co_data(chn) == 0)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003136 return 1;
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003137
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003138 if (l < len) {
3139 /* If we are waiting for space in the response buffer, we
3140 * must set the flag WAKERESWR. This flag required the task
3141 * wake up if any activity is detected on the response buffer.
3142 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003143 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003144 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003145 else
3146 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003147 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003148 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003149
3150 return 1;
3151}
3152
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003153/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003154 * yield the LUA process, and resume it without checking the
3155 * input arguments.
3156 */
3157__LJMP static int hlua_channel_send(lua_State *L)
3158{
3159 MAY_LJMP(check_args(L, 2, "send"));
3160 lua_pushinteger(L, 0);
3161
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003162 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003163}
3164
3165/* This function forward and amount of butes. The data pass from
3166 * the input side of the buffer to the output side, and can be
3167 * forwarded. This function never fails.
3168 *
3169 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003170 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003171 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003172__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003173{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003174 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003175 int len;
3176 int l;
3177 int max;
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003178 struct hlua *hlua = hlua_gethlua(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003179
3180 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003181
Thierry Fournier77016da2020-08-15 14:35:51 +02003182 if (chn_strm(chn)->be->mode == PR_MODE_HTTP) {
3183 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003184 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003185 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003186
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003187 len = MAY_LJMP(luaL_checkinteger(L, 2));
3188 l = MAY_LJMP(luaL_checkinteger(L, -1));
3189
3190 max = len - l;
Willy Tarreaua79021a2018-06-15 18:07:57 +02003191 if (max > ci_data(chn))
3192 max = ci_data(chn);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003193 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003194 l += max;
3195
3196 lua_pop(L, 1);
3197 lua_pushinteger(L, l);
3198
3199 /* Check if it miss bytes to forward. */
3200 if (l < len) {
3201 /* The the input channel or the output channel are closed, we
3202 * must return the amount of data forwarded.
3203 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003204 if (channel_input_closed(chn) || channel_output_closed(chn))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003205 return 1;
3206
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003207 /* If we are waiting for space data in the response buffer, we
3208 * must set the flag WAKERESWR. This flag required the task
3209 * wake up if any activity is detected on the response buffer.
3210 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003211 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003212 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003213 else
3214 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003215
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003216 /* Otherwise, we can yield waiting for new data in the inpout side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02003217 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003218 }
3219
3220 return 1;
3221}
3222
3223/* Just check the input and prepare the stack for the previous
3224 * function "hlua_channel_forward_yield"
3225 */
3226__LJMP static int hlua_channel_forward(lua_State *L)
3227{
3228 MAY_LJMP(check_args(L, 2, "forward"));
3229 MAY_LJMP(hlua_checkchannel(L, 1));
3230 MAY_LJMP(luaL_checkinteger(L, 2));
3231
3232 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003233 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003234}
3235
3236/* Just returns the number of bytes available in the input
3237 * side of the buffer. This function never fails.
3238 */
3239__LJMP static int hlua_channel_get_in_len(lua_State *L)
3240{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003241 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003242
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003243 MAY_LJMP(check_args(L, 1, "get_in_len"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003244 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta3ceac12018-12-14 13:39:09 +01003245 if (IS_HTX_STRM(chn_strm(chn))) {
3246 struct htx *htx = htxbuf(&chn->buf);
3247 lua_pushinteger(L, htx->data - co_data(chn));
3248 }
3249 else
3250 lua_pushinteger(L, ci_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003251 return 1;
3252}
3253
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003254/* Returns true if the channel is full. */
3255__LJMP static int hlua_channel_is_full(lua_State *L)
3256{
3257 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003258
3259 MAY_LJMP(check_args(L, 1, "is_full"));
3260 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01003261 /* ignore the reserve, we are not on a producer side (ie in an
3262 * applet).
3263 */
3264 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003265 return 1;
3266}
3267
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01003268/* Returns true if the channel is the response channel. */
3269__LJMP static int hlua_channel_is_resp(lua_State *L)
3270{
3271 struct channel *chn;
3272
3273 MAY_LJMP(check_args(L, 1, "is_resp"));
3274 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3275
3276 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
3277 return 1;
3278}
3279
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003280/* Just returns the number of bytes available in the output
3281 * side of the buffer. This function never fails.
3282 */
3283__LJMP static int hlua_channel_get_out_len(lua_State *L)
3284{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003285 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003286
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003287 MAY_LJMP(check_args(L, 1, "get_out_len"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003288 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Willy Tarreaua79021a2018-06-15 18:07:57 +02003289 lua_pushinteger(L, co_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003290 return 1;
3291}
3292
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003293/*
3294 *
3295 *
3296 * Class Fetches
3297 *
3298 *
3299 */
3300
3301/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003302 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003303 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003304__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003305{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003306 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003307}
3308
3309/* This function creates and push in the stack a fetch object according
3310 * with a current TXN.
3311 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003312static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003313{
Willy Tarreau7073c472015-04-06 11:15:40 +02003314 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003315
3316 /* Check stack size. */
3317 if (!lua_checkstack(L, 3))
3318 return 0;
3319
3320 /* Create the object: obj[0] = userdata.
3321 * Note that the base of the Fetches object is the
3322 * transaction object.
3323 */
3324 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003325 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003326 lua_rawseti(L, -2, 0);
3327
Willy Tarreau7073c472015-04-06 11:15:40 +02003328 hsmp->s = txn->s;
3329 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003330 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003331 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003332
3333 /* Pop a class sesison metatable and affect it to the userdata. */
3334 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
3335 lua_setmetatable(L, -2);
3336
3337 return 1;
3338}
3339
3340/* This function is an LUA binding. It is called with each sample-fetch.
3341 * It uses closure argument to store the associated sample-fetch. It
3342 * returns only one argument or throws an error. An error is thrown
3343 * only if an error is encountered during the argument parsing. If
3344 * the "sample-fetch" function fails, nil is returned.
3345 */
3346__LJMP static int hlua_run_sample_fetch(lua_State *L)
3347{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003348 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01003349 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003350 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003351 int i;
3352 struct sample smp;
3353
3354 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003355 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003356
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003357 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003358 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003359
Thierry FOURNIERca988662015-12-20 18:43:03 +01003360 /* Check execution authorization. */
3361 if (f->use & SMP_USE_HTTP_ANY &&
3362 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
3363 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
3364 "is not available in Lua services", f->kw);
3365 WILL_LJMP(lua_error(L));
3366 }
3367
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003368 /* Get extra arguments. */
3369 for (i = 0; i < lua_gettop(L) - 1; i++) {
3370 if (i >= ARGM_NBARGS)
3371 break;
3372 hlua_lua2arg(L, i + 2, &args[i]);
3373 }
3374 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003375 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003376
3377 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003378 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003379
3380 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01003381 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003382 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003383 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003384 }
3385
3386 /* Initialise the sample. */
3387 memset(&smp, 0, sizeof(smp));
3388
3389 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01003390 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02003391 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003392 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003393 lua_pushstring(L, "");
3394 else
3395 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003396 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003397 }
3398
3399 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003400 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003401 hlua_smp2lua_str(L, &smp);
3402 else
3403 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003404
3405 end:
3406 for (i = 0; args[i].type != ARGT_STOP; i++) {
3407 if (args[i].type == ARGT_STR)
3408 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003409 else if (args[i].type == ARGT_REG)
3410 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003411 }
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003412 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003413
3414 error:
3415 for (i = 0; args[i].type != ARGT_STOP; i++) {
3416 if (args[i].type == ARGT_STR)
3417 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003418 else if (args[i].type == ARGT_REG)
3419 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003420 }
3421 WILL_LJMP(lua_error(L));
3422 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003423}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003424
3425/*
3426 *
3427 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003428 * Class Converters
3429 *
3430 *
3431 */
3432
3433/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003434 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003435 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003436__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003437{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003438 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003439}
3440
3441/* This function creates and push in the stack a Converters object
3442 * according with a current TXN.
3443 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003444static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003445{
Willy Tarreau7073c472015-04-06 11:15:40 +02003446 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003447
3448 /* Check stack size. */
3449 if (!lua_checkstack(L, 3))
3450 return 0;
3451
3452 /* Create the object: obj[0] = userdata.
3453 * Note that the base of the Converters object is the
3454 * same than the TXN object.
3455 */
3456 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003457 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003458 lua_rawseti(L, -2, 0);
3459
Willy Tarreau7073c472015-04-06 11:15:40 +02003460 hsmp->s = txn->s;
3461 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003462 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003463 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003464
Willy Tarreau87b09662015-04-03 00:22:06 +02003465 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003466 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
3467 lua_setmetatable(L, -2);
3468
3469 return 1;
3470}
3471
3472/* This function is an LUA binding. It is called with each converter.
3473 * It uses closure argument to store the associated converter. It
3474 * returns only one argument or throws an error. An error is thrown
3475 * only if an error is encountered during the argument parsing. If
3476 * the converter function function fails, nil is returned.
3477 */
3478__LJMP static int hlua_run_sample_conv(lua_State *L)
3479{
Willy Tarreauda5f1082015-04-06 11:17:13 +02003480 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003481 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003482 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003483 int i;
3484 struct sample smp;
3485
3486 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003487 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003488
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003489 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003490 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003491
3492 /* Get extra arguments. */
3493 for (i = 0; i < lua_gettop(L) - 2; i++) {
3494 if (i >= ARGM_NBARGS)
3495 break;
3496 hlua_lua2arg(L, i + 3, &args[i]);
3497 }
3498 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003499 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003500
3501 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003502 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003503
3504 /* Run the special args checker. */
3505 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
3506 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003507 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003508 }
3509
3510 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003511 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003512 if (!hlua_lua2smp(L, 2, &smp)) {
3513 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003514 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003515 }
3516
Willy Tarreau1777ea62016-03-10 16:15:46 +01003517 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
3518
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003519 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003520 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003521 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003522 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003523 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003524 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003525 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
3526 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003527 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003528 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003529 }
3530
3531 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02003532 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003533 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003534 lua_pushstring(L, "");
3535 else
Willy Tarreaua678b432015-08-28 10:14:59 +02003536 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003537 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003538 }
3539
3540 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003541 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003542 hlua_smp2lua_str(L, &smp);
3543 else
3544 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003545 end:
3546 for (i = 0; args[i].type != ARGT_STOP; i++) {
3547 if (args[i].type == ARGT_STR)
3548 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003549 else if (args[i].type == ARGT_REG)
3550 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003551 }
Willy Tarreaua678b432015-08-28 10:14:59 +02003552 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003553
3554 error:
3555 for (i = 0; args[i].type != ARGT_STOP; i++) {
3556 if (args[i].type == ARGT_STR)
3557 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003558 else if (args[i].type == ARGT_REG)
3559 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003560 }
3561 WILL_LJMP(lua_error(L));
3562 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003563}
3564
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003565/*
3566 *
3567 *
3568 * Class AppletTCP
3569 *
3570 *
3571 */
3572
3573/* Returns a struct hlua_txn if the stack entry "ud" is
3574 * a class stream, otherwise it throws an error.
3575 */
3576__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
3577{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003578 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003579}
3580
3581/* This function creates and push in the stack an Applet object
3582 * according with a current TXN.
3583 */
3584static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
3585{
3586 struct hlua_appctx *appctx;
3587 struct stream_interface *si = ctx->owner;
3588 struct stream *s = si_strm(si);
3589 struct proxy *p = s->be;
3590
3591 /* Check stack size. */
3592 if (!lua_checkstack(L, 3))
3593 return 0;
3594
3595 /* Create the object: obj[0] = userdata.
3596 * Note that the base of the Converters object is the
3597 * same than the TXN object.
3598 */
3599 lua_newtable(L);
3600 appctx = lua_newuserdata(L, sizeof(*appctx));
3601 lua_rawseti(L, -2, 0);
3602 appctx->appctx = ctx;
3603 appctx->htxn.s = s;
3604 appctx->htxn.p = p;
3605
3606 /* Create the "f" field that contains a list of fetches. */
3607 lua_pushstring(L, "f");
3608 if (!hlua_fetches_new(L, &appctx->htxn, 0))
3609 return 0;
3610 lua_settable(L, -3);
3611
3612 /* Create the "sf" field that contains a list of stringsafe fetches. */
3613 lua_pushstring(L, "sf");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003614 if (!hlua_fetches_new(L, &appctx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003615 return 0;
3616 lua_settable(L, -3);
3617
3618 /* Create the "c" field that contains a list of converters. */
3619 lua_pushstring(L, "c");
3620 if (!hlua_converters_new(L, &appctx->htxn, 0))
3621 return 0;
3622 lua_settable(L, -3);
3623
3624 /* Create the "sc" field that contains a list of stringsafe converters. */
3625 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003626 if (!hlua_converters_new(L, &appctx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003627 return 0;
3628 lua_settable(L, -3);
3629
3630 /* Pop a class stream metatable and affect it to the table. */
3631 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
3632 lua_setmetatable(L, -2);
3633
3634 return 1;
3635}
3636
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003637__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
3638{
3639 struct hlua_appctx *appctx;
3640 struct stream *s;
3641 const char *name;
3642 size_t len;
3643 struct sample smp;
3644
Tim Duesterhus4e172c92020-05-19 13:49:42 +02003645 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
3646 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003647
3648 /* It is useles to retrieve the stream, but this function
3649 * runs only in a stream context.
3650 */
3651 appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3652 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
3653 s = appctx->htxn.s;
3654
3655 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003656 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003657 hlua_lua2smp(L, 3, &smp);
3658
3659 /* Store the sample in a variable. */
3660 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02003661
3662 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
3663 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
3664 else
3665 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
3666
Tim Duesterhus84ebc132020-05-19 13:49:41 +02003667 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003668}
3669
3670__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
3671{
3672 struct hlua_appctx *appctx;
3673 struct stream *s;
3674 const char *name;
3675 size_t len;
3676 struct sample smp;
3677
3678 MAY_LJMP(check_args(L, 2, "unset_var"));
3679
3680 /* It is useles to retrieve the stream, but this function
3681 * runs only in a stream context.
3682 */
3683 appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3684 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
3685 s = appctx->htxn.s;
3686
3687 /* Unset the variable. */
3688 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02003689 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
3690 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003691}
3692
3693__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
3694{
3695 struct hlua_appctx *appctx;
3696 struct stream *s;
3697 const char *name;
3698 size_t len;
3699 struct sample smp;
3700
3701 MAY_LJMP(check_args(L, 2, "get_var"));
3702
3703 /* It is useles to retrieve the stream, but this function
3704 * runs only in a stream context.
3705 */
3706 appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3707 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
3708 s = appctx->htxn.s;
3709
3710 smp_set_owner(&smp, s->be, s->sess, s, 0);
3711 if (!vars_get_by_name(name, len, &smp)) {
3712 lua_pushnil(L);
3713 return 1;
3714 }
3715
3716 return hlua_smp2lua(L, &smp);
3717}
3718
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003719__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
3720{
3721 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3722 struct stream *s = appctx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01003723 struct hlua *hlua;
3724
3725 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01003726 if (!s->hlua)
3727 return 0;
3728 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003729
3730 MAY_LJMP(check_args(L, 2, "set_priv"));
3731
3732 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02003733 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003734
3735 /* Get and store new value. */
3736 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
3737 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
3738
3739 return 0;
3740}
3741
3742__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
3743{
3744 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3745 struct stream *s = appctx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01003746 struct hlua *hlua;
3747
3748 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01003749 if (!s->hlua) {
3750 lua_pushnil(L);
3751 return 1;
3752 }
3753 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003754
3755 /* Push configuration index in the stack. */
3756 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
3757
3758 return 1;
3759}
3760
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003761/* If expected data not yet available, it returns a yield. This function
3762 * consumes the data in the buffer. It returns a string containing the
3763 * data. This string can be empty.
3764 */
3765__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
3766{
3767 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3768 struct stream_interface *si = appctx->appctx->owner;
3769 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02003770 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003771 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02003772 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003773 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003774
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003775 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003776 ret = co_getline_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003777
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003778 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003779 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003780 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003781 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003782 }
3783
3784 /* End of data: commit the total strings and return. */
3785 if (ret < 0) {
3786 luaL_pushresult(&appctx->b);
3787 return 1;
3788 }
3789
3790 /* Ensure that the block 2 length is usable. */
3791 if (ret == 1)
3792 len2 = 0;
3793
3794 /* dont check the max length read and dont check. */
3795 luaL_addlstring(&appctx->b, blk1, len1);
3796 luaL_addlstring(&appctx->b, blk2, len2);
3797
3798 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003799 co_skip(si_oc(si), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003800 luaL_pushresult(&appctx->b);
3801 return 1;
3802}
3803
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003804/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003805__LJMP static int hlua_applet_tcp_getline(lua_State *L)
3806{
3807 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3808
3809 /* Initialise the string catenation. */
3810 luaL_buffinit(L, &appctx->b);
3811
3812 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
3813}
3814
3815/* If expected data not yet available, it returns a yield. This function
3816 * consumes the data in the buffer. It returns a string containing the
3817 * data. This string can be empty.
3818 */
3819__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
3820{
3821 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3822 struct stream_interface *si = appctx->appctx->owner;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003823 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003824 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02003825 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003826 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02003827 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003828 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003829
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003830 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003831 ret = co_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003832
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003833 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003834 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003835 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003836 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003837 }
3838
3839 /* End of data: commit the total strings and return. */
3840 if (ret < 0) {
3841 luaL_pushresult(&appctx->b);
3842 return 1;
3843 }
3844
3845 /* Ensure that the block 2 length is usable. */
3846 if (ret == 1)
3847 len2 = 0;
3848
3849 if (len == -1) {
3850
3851 /* If len == -1, catenate all the data avalaile and
3852 * yield because we want to get all the data until
3853 * the end of data stream.
3854 */
3855 luaL_addlstring(&appctx->b, blk1, len1);
3856 luaL_addlstring(&appctx->b, blk2, len2);
Willy Tarreau06d80a92017-10-19 14:32:15 +02003857 co_skip(si_oc(si), len1 + len2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003858 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003859 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003860
3861 } else {
3862
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003863 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003864 if (len1 > len)
3865 len1 = len;
3866 luaL_addlstring(&appctx->b, blk1, len1);
3867 len -= len1;
3868
3869 /* Copy the second block. */
3870 if (len2 > len)
3871 len2 = len;
3872 luaL_addlstring(&appctx->b, blk2, len2);
3873 len -= len2;
3874
3875 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003876 co_skip(si_oc(si), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003877
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003878 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003879 if (len > 0) {
3880 lua_pushinteger(L, len);
3881 lua_replace(L, 2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003882 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003883 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003884 }
3885
3886 /* return the result. */
3887 luaL_pushresult(&appctx->b);
3888 return 1;
3889 }
3890
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003891 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003892 hlua_pusherror(L, "Lua: internal error");
3893 WILL_LJMP(lua_error(L));
3894 return 0;
3895}
3896
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003897/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003898__LJMP static int hlua_applet_tcp_recv(lua_State *L)
3899{
3900 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3901 int len = -1;
3902
3903 if (lua_gettop(L) > 2)
3904 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
3905 if (lua_gettop(L) >= 2) {
3906 len = MAY_LJMP(luaL_checkinteger(L, 2));
3907 lua_pop(L, 1);
3908 }
3909
3910 /* Confirm or set the required length */
3911 lua_pushinteger(L, len);
3912
3913 /* Initialise the string catenation. */
3914 luaL_buffinit(L, &appctx->b);
3915
3916 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
3917}
3918
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003919/* Append data in the output side of the buffer. This data is immediately
3920 * sent. The function returns the amount of data written. If the buffer
3921 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003922 * if the channel is closed.
3923 */
3924__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
3925{
3926 size_t len;
3927 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3928 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
3929 int l = MAY_LJMP(luaL_checkinteger(L, 3));
3930 struct stream_interface *si = appctx->appctx->owner;
3931 struct channel *chn = si_ic(si);
3932 int max;
3933
3934 /* Get the max amount of data which can write as input in the channel. */
3935 max = channel_recv_max(chn);
3936 if (max > (len - l))
3937 max = len - l;
3938
3939 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003940 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003941
3942 /* update counters. */
3943 l += max;
3944 lua_pop(L, 1);
3945 lua_pushinteger(L, l);
3946
3947 /* If some data is not send, declares the situation to the
3948 * applet, and returns a yield.
3949 */
3950 if (l < len) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003951 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003952 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003953 }
3954
3955 return 1;
3956}
3957
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003958/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003959 * yield the LUA process, and resume it without checking the
3960 * input arguments.
3961 */
3962__LJMP static int hlua_applet_tcp_send(lua_State *L)
3963{
3964 MAY_LJMP(check_args(L, 2, "send"));
3965 lua_pushinteger(L, 0);
3966
3967 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
3968}
3969
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003970/*
3971 *
3972 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02003973 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01003974 *
3975 *
3976 */
3977
3978/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003979 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01003980 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02003981__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01003982{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003983 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01003984}
3985
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02003986/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01003987 * according with a current TXN.
3988 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02003989static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01003990{
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02003991 struct hlua_appctx *appctx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01003992 struct hlua_txn htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02003993 struct stream_interface *si = ctx->owner;
3994 struct stream *s = si_strm(si);
3995 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02003996 struct htx *htx;
3997 struct htx_blk *blk;
3998 struct htx_sl *sl;
3999 struct ist path;
4000 unsigned long long len = 0;
4001 int32_t pos;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004002
4003 /* Check stack size. */
4004 if (!lua_checkstack(L, 3))
4005 return 0;
4006
4007 /* Create the object: obj[0] = userdata.
4008 * Note that the base of the Converters object is the
4009 * same than the TXN object.
4010 */
4011 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004012 appctx = lua_newuserdata(L, sizeof(*appctx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004013 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004014 appctx->appctx = ctx;
4015 appctx->appctx->ctx.hlua_apphttp.status = 200; /* Default status code returned. */
Robin H. Johnson52f5db22017-01-01 13:10:52 -08004016 appctx->appctx->ctx.hlua_apphttp.reason = NULL; /* Use default reason based on status */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004017 appctx->htxn.s = s;
4018 appctx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004019
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004020 /* Create the "f" field that contains a list of fetches. */
4021 lua_pushstring(L, "f");
4022 if (!hlua_fetches_new(L, &appctx->htxn, 0))
4023 return 0;
4024 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004025
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004026 /* Create the "sf" field that contains a list of stringsafe fetches. */
4027 lua_pushstring(L, "sf");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004028 if (!hlua_fetches_new(L, &appctx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004029 return 0;
4030 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004031
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004032 /* Create the "c" field that contains a list of converters. */
4033 lua_pushstring(L, "c");
4034 if (!hlua_converters_new(L, &appctx->htxn, 0))
4035 return 0;
4036 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004037
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004038 /* Create the "sc" field that contains a list of stringsafe converters. */
4039 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01004040 if (!hlua_converters_new(L, &appctx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004041 return 0;
4042 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004043
Christopher Fauleta2097962019-07-15 16:25:33 +02004044 htx = htxbuf(&s->req.buf);
4045 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004046 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004047 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004048
Christopher Fauleta2097962019-07-15 16:25:33 +02004049 /* Stores the request method. */
4050 lua_pushstring(L, "method");
4051 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4052 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004053
Christopher Fauleta2097962019-07-15 16:25:33 +02004054 /* Stores the http version. */
4055 lua_pushstring(L, "version");
4056 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4057 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004058
Christopher Fauleta2097962019-07-15 16:25:33 +02004059 /* creates an array of headers. hlua_http_get_headers() crates and push
4060 * the array on the top of the stack.
4061 */
4062 lua_pushstring(L, "headers");
4063 htxn.s = s;
4064 htxn.p = px;
4065 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004066 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004067 return 0;
4068 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004069
Christopher Fauleta2097962019-07-15 16:25:33 +02004070 path = http_get_path(htx_sl_req_uri(sl));
Tim Duesterhused526372020-03-05 17:56:33 +01004071 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004072 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004073
Christopher Fauleta2097962019-07-15 16:25:33 +02004074 p = path.ptr;
4075 end = path.ptr + path.len;
4076 q = p;
4077 while (q < end && *q != '?')
4078 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004079
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004080 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004081 lua_pushstring(L, "path");
4082 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004083 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004084
Christopher Fauleta2097962019-07-15 16:25:33 +02004085 /* Stores the query string. */
4086 lua_pushstring(L, "qs");
4087 if (*q == '?')
4088 q++;
4089 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004090 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004091 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004092
Christopher Fauleta2097962019-07-15 16:25:33 +02004093 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4094 struct htx_blk *blk = htx_get_blk(htx, pos);
4095 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004096
Christopher Fauleta2097962019-07-15 16:25:33 +02004097 if (type == HTX_BLK_EOM || type == HTX_BLK_TLR || type == HTX_BLK_EOT)
4098 break;
4099 if (type == HTX_BLK_DATA)
4100 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004101 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004102 if (htx->extra != ULLONG_MAX)
4103 len += htx->extra;
4104
4105 /* Stores the request path. */
4106 lua_pushstring(L, "length");
4107 lua_pushinteger(L, len);
4108 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004109
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004110 /* Create an empty array of HTTP request headers. */
4111 lua_pushstring(L, "response");
4112 lua_newtable(L);
4113 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004114
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004115 /* Pop a class stream metatable and affect it to the table. */
4116 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4117 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004118
4119 return 1;
4120}
4121
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004122__LJMP static int hlua_applet_http_set_var(lua_State *L)
4123{
4124 struct hlua_appctx *appctx;
4125 struct stream *s;
4126 const char *name;
4127 size_t len;
4128 struct sample smp;
4129
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004130 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4131 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004132
4133 /* It is useles to retrieve the stream, but this function
4134 * runs only in a stream context.
4135 */
4136 appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4137 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
4138 s = appctx->htxn.s;
4139
4140 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004141 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004142 hlua_lua2smp(L, 3, &smp);
4143
4144 /* Store the sample in a variable. */
4145 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004146
4147 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4148 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4149 else
4150 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4151
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004152 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004153}
4154
4155__LJMP static int hlua_applet_http_unset_var(lua_State *L)
4156{
4157 struct hlua_appctx *appctx;
4158 struct stream *s;
4159 const char *name;
4160 size_t len;
4161 struct sample smp;
4162
4163 MAY_LJMP(check_args(L, 2, "unset_var"));
4164
4165 /* It is useles to retrieve the stream, but this function
4166 * runs only in a stream context.
4167 */
4168 appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4169 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
4170 s = appctx->htxn.s;
4171
4172 /* Unset the variable. */
4173 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004174 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4175 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004176}
4177
4178__LJMP static int hlua_applet_http_get_var(lua_State *L)
4179{
4180 struct hlua_appctx *appctx;
4181 struct stream *s;
4182 const char *name;
4183 size_t len;
4184 struct sample smp;
4185
4186 MAY_LJMP(check_args(L, 2, "get_var"));
4187
4188 /* It is useles to retrieve the stream, but this function
4189 * runs only in a stream context.
4190 */
4191 appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4192 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
4193 s = appctx->htxn.s;
4194
4195 smp_set_owner(&smp, s->be, s->sess, s, 0);
4196 if (!vars_get_by_name(name, len, &smp)) {
4197 lua_pushnil(L);
4198 return 1;
4199 }
4200
4201 return hlua_smp2lua(L, &smp);
4202}
4203
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004204__LJMP static int hlua_applet_http_set_priv(lua_State *L)
4205{
4206 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4207 struct stream *s = appctx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004208 struct hlua *hlua;
4209
4210 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004211 if (!s->hlua)
4212 return 0;
4213 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004214
4215 MAY_LJMP(check_args(L, 2, "set_priv"));
4216
4217 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004218 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004219
4220 /* Get and store new value. */
4221 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4222 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4223
4224 return 0;
4225}
4226
4227__LJMP static int hlua_applet_http_get_priv(lua_State *L)
4228{
4229 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4230 struct stream *s = appctx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004231 struct hlua *hlua;
4232
4233 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004234 if (!s->hlua) {
4235 lua_pushnil(L);
4236 return 1;
4237 }
4238 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004239
4240 /* Push configuration index in the stack. */
4241 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4242
4243 return 1;
4244}
4245
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004246/* If expected data not yet available, it returns a yield. This function
4247 * consumes the data in the buffer. It returns a string containing the
4248 * data. This string can be empty.
4249 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004250__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004251{
4252 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4253 struct stream_interface *si = appctx->appctx->owner;
4254 struct channel *req = si_oc(si);
4255 struct htx *htx;
4256 struct htx_blk *blk;
4257 size_t count;
4258 int stop = 0;
4259
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004260 htx = htx_from_buf(&req->buf);
4261 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02004262 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01004263
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004264 while (count && !stop && blk) {
4265 enum htx_blk_type type = htx_get_blk_type(blk);
4266 uint32_t sz = htx_get_blksz(blk);
4267 struct ist v;
4268 uint32_t vlen;
4269 char *nl;
4270
Christopher Faulete461e342018-12-18 16:43:35 +01004271 if (type == HTX_BLK_EOM) {
4272 stop = 1;
4273 break;
4274 }
4275
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004276 vlen = sz;
4277 if (vlen > count) {
4278 if (type != HTX_BLK_DATA)
4279 break;
4280 vlen = count;
4281 }
4282
4283 switch (type) {
4284 case HTX_BLK_UNUSED:
4285 break;
4286
4287 case HTX_BLK_DATA:
4288 v = htx_get_blk_value(htx, blk);
4289 v.len = vlen;
4290 nl = istchr(v, '\n');
4291 if (nl != NULL) {
4292 stop = 1;
4293 vlen = nl - v.ptr + 1;
4294 }
4295 luaL_addlstring(&appctx->b, v.ptr, vlen);
4296 break;
4297
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004298 case HTX_BLK_TLR:
4299 case HTX_BLK_EOM:
4300 stop = 1;
4301 break;
4302
4303 default:
4304 break;
4305 }
4306
4307 co_set_data(req, co_data(req) - vlen);
4308 count -= vlen;
4309 if (sz == vlen)
4310 blk = htx_remove_blk(htx, blk);
4311 else {
4312 htx_cut_data_blk(htx, blk, vlen);
4313 break;
4314 }
4315 }
4316
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004317 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004318 if (!stop) {
4319 si_cant_get(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004320 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004321 }
4322
4323 /* return the result. */
4324 luaL_pushresult(&appctx->b);
4325 return 1;
4326}
4327
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004328
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004329/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004330__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004331{
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004332 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004333
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004334 /* Initialise the string catenation. */
4335 luaL_buffinit(L, &appctx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004336
Christopher Fauleta2097962019-07-15 16:25:33 +02004337 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004338}
4339
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004340/* If expected data not yet available, it returns a yield. This function
4341 * consumes the data in the buffer. It returns a string containing the
4342 * data. This string can be empty.
4343 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004344__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004345{
4346 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4347 struct stream_interface *si = appctx->appctx->owner;
4348 struct channel *req = si_oc(si);
4349 struct htx *htx;
4350 struct htx_blk *blk;
4351 size_t count;
4352 int len;
4353
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004354 htx = htx_from_buf(&req->buf);
4355 len = MAY_LJMP(luaL_checkinteger(L, 2));
4356 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02004357 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004358 while (count && len && blk) {
4359 enum htx_blk_type type = htx_get_blk_type(blk);
4360 uint32_t sz = htx_get_blksz(blk);
4361 struct ist v;
4362 uint32_t vlen;
4363
Christopher Faulete461e342018-12-18 16:43:35 +01004364 if (type == HTX_BLK_EOM) {
4365 len = 0;
4366 break;
4367 }
4368
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004369 vlen = sz;
4370 if (len > 0 && vlen > len)
4371 vlen = len;
4372 if (vlen > count) {
4373 if (type != HTX_BLK_DATA)
4374 break;
4375 vlen = count;
4376 }
4377
4378 switch (type) {
4379 case HTX_BLK_UNUSED:
4380 break;
4381
4382 case HTX_BLK_DATA:
4383 v = htx_get_blk_value(htx, blk);
4384 luaL_addlstring(&appctx->b, v.ptr, vlen);
4385 break;
4386
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004387 case HTX_BLK_TLR:
4388 case HTX_BLK_EOM:
4389 len = 0;
4390 break;
4391
4392 default:
4393 break;
4394 }
4395
4396 co_set_data(req, co_data(req) - vlen);
4397 count -= vlen;
4398 if (len > 0)
4399 len -= vlen;
4400 if (sz == vlen)
4401 blk = htx_remove_blk(htx, blk);
4402 else {
4403 htx_cut_data_blk(htx, blk, vlen);
4404 break;
4405 }
4406 }
4407
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004408 htx_to_buf(htx, &req->buf);
4409
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004410 /* If we are no other data available, yield waiting for new data. */
4411 if (len) {
4412 if (len > 0) {
4413 lua_pushinteger(L, len);
4414 lua_replace(L, 2);
4415 }
4416 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004417 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004418 }
4419
4420 /* return the result. */
4421 luaL_pushresult(&appctx->b);
4422 return 1;
4423}
4424
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004425/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004426__LJMP static int hlua_applet_http_recv(lua_State *L)
4427{
4428 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4429 int len = -1;
4430
4431 /* Check arguments. */
4432 if (lua_gettop(L) > 2)
4433 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4434 if (lua_gettop(L) >= 2) {
4435 len = MAY_LJMP(luaL_checkinteger(L, 2));
4436 lua_pop(L, 1);
4437 }
4438
Christopher Fauleta2097962019-07-15 16:25:33 +02004439 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004440
Christopher Fauleta2097962019-07-15 16:25:33 +02004441 /* Initialise the string catenation. */
4442 luaL_buffinit(L, &appctx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004443
Christopher Fauleta2097962019-07-15 16:25:33 +02004444 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004445}
4446
4447/* Append data in the output side of the buffer. This data is immediately
4448 * sent. The function returns the amount of data written. If the buffer
4449 * cannot contain the data, the function yields. The function returns -1
4450 * if the channel is closed.
4451 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004452__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004453{
4454 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4455 struct stream_interface *si = appctx->appctx->owner;
4456 struct channel *res = si_ic(si);
4457 struct htx *htx = htx_from_buf(&res->buf);
4458 const char *data;
4459 size_t len;
4460 int l = MAY_LJMP(luaL_checkinteger(L, 3));
4461 int max;
4462
Christopher Faulet9060fc02019-07-03 11:39:30 +02004463 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004464 if (!max)
4465 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004466
4467 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
4468
4469 /* Get the max amount of data which can write as input in the channel. */
4470 if (max > (len - l))
4471 max = len - l;
4472
4473 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02004474 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004475 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004476
4477 /* update counters. */
4478 l += max;
4479 lua_pop(L, 1);
4480 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004481
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004482 /* If some data is not send, declares the situation to the
4483 * applet, and returns a yield.
4484 */
4485 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004486 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004487 htx_to_buf(htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004488 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004489 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004490 }
4491
Christopher Fauleta2097962019-07-15 16:25:33 +02004492 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004493 return 1;
4494}
4495
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004496/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004497 * yield the LUA process, and resume it without checking the
4498 * input arguments.
4499 */
4500__LJMP static int hlua_applet_http_send(lua_State *L)
4501{
4502 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004503
4504 /* We want to send some data. Headers must be sent. */
4505 if (!(appctx->appctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
4506 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
4507 WILL_LJMP(lua_error(L));
4508 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004509
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004510 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004511 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004512
Christopher Fauleta2097962019-07-15 16:25:33 +02004513 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004514}
4515
4516__LJMP static int hlua_applet_http_addheader(lua_State *L)
4517{
4518 const char *name;
4519 int ret;
4520
4521 MAY_LJMP(hlua_checkapplet_http(L, 1));
4522 name = MAY_LJMP(luaL_checkstring(L, 2));
4523 MAY_LJMP(luaL_checkstring(L, 3));
4524
4525 /* Push in the stack the "response" entry. */
4526 ret = lua_getfield(L, 1, "response");
4527 if (ret != LUA_TTABLE) {
4528 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
4529 "is expected as an array. %s found", lua_typename(L, ret));
4530 WILL_LJMP(lua_error(L));
4531 }
4532
4533 /* check if the header is already registered if it is not
4534 * the case, register it.
4535 */
4536 ret = lua_getfield(L, -1, name);
4537 if (ret == LUA_TNIL) {
4538
4539 /* Entry not found. */
4540 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
4541
4542 /* Insert the new header name in the array in the top of the stack.
4543 * It left the new array in the top of the stack.
4544 */
4545 lua_newtable(L);
4546 lua_pushvalue(L, 2);
4547 lua_pushvalue(L, -2);
4548 lua_settable(L, -4);
4549
4550 } else if (ret != LUA_TTABLE) {
4551
4552 /* corruption error. */
4553 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
4554 "is expected as an array. %s found", name, lua_typename(L, ret));
4555 WILL_LJMP(lua_error(L));
4556 }
4557
4558 /* Now the top od thestack is an array of values. We push
4559 * the header value as new entry.
4560 */
4561 lua_pushvalue(L, 3);
4562 ret = lua_rawlen(L, -2);
4563 lua_rawseti(L, -2, ret + 1);
4564 lua_pushboolean(L, 1);
4565 return 1;
4566}
4567
4568__LJMP static int hlua_applet_http_status(lua_State *L)
4569{
4570 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4571 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08004572 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004573
4574 if (status < 100 || status > 599) {
4575 lua_pushboolean(L, 0);
4576 return 1;
4577 }
4578
4579 appctx->appctx->ctx.hlua_apphttp.status = status;
Robin H. Johnson52f5db22017-01-01 13:10:52 -08004580 appctx->appctx->ctx.hlua_apphttp.reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004581 lua_pushboolean(L, 1);
4582 return 1;
4583}
4584
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004585
Christopher Fauleta2097962019-07-15 16:25:33 +02004586__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004587{
4588 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4589 struct stream_interface *si = appctx->appctx->owner;
4590 struct channel *res = si_ic(si);
4591 struct htx *htx;
4592 struct htx_sl *sl;
4593 struct h1m h1m;
4594 const char *status, *reason;
4595 const char *name, *value;
4596 size_t nlen, vlen;
4597 unsigned int flags;
4598
4599 /* Send the message at once. */
4600 htx = htx_from_buf(&res->buf);
4601 h1m_init_res(&h1m);
4602
4603 /* Use the same http version than the request. */
4604 status = ultoa_r(appctx->appctx->ctx.hlua_apphttp.status, trash.area, trash.size);
4605 reason = appctx->appctx->ctx.hlua_apphttp.reason;
4606 if (reason == NULL)
4607 reason = http_get_reason(appctx->appctx->ctx.hlua_apphttp.status);
4608 if (appctx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11) {
4609 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
4610 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
4611 }
4612 else {
4613 flags = HTX_SL_F_IS_RESP;
4614 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
4615 }
4616 if (!sl) {
4617 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
4618 appctx->appctx->rule->arg.hlua_rule->fcn.name);
4619 WILL_LJMP(lua_error(L));
4620 }
4621 sl->info.res.status = appctx->appctx->ctx.hlua_apphttp.status;
4622
4623 /* Get the array associated to the field "response" in the object AppletHTTP. */
4624 lua_pushvalue(L, 0);
4625 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
4626 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
4627 appctx->appctx->rule->arg.hlua_rule->fcn.name);
4628 WILL_LJMP(lua_error(L));
4629 }
4630
4631 /* Browse the list of headers. */
4632 lua_pushnil(L);
4633 while(lua_next(L, -2) != 0) {
4634 /* We expect a string as -2. */
4635 if (lua_type(L, -2) != LUA_TSTRING) {
4636 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
4637 appctx->appctx->rule->arg.hlua_rule->fcn.name,
4638 lua_typename(L, lua_type(L, -2)));
4639 WILL_LJMP(lua_error(L));
4640 }
4641 name = lua_tolstring(L, -2, &nlen);
4642
4643 /* We expect an array as -1. */
4644 if (lua_type(L, -1) != LUA_TTABLE) {
4645 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'] element must be an table. got %s.\n",
4646 appctx->appctx->rule->arg.hlua_rule->fcn.name,
4647 name,
4648 lua_typename(L, lua_type(L, -1)));
4649 WILL_LJMP(lua_error(L));
4650 }
4651
4652 /* Browse the table who is on the top of the stack. */
4653 lua_pushnil(L);
4654 while(lua_next(L, -2) != 0) {
4655 int id;
4656
4657 /* We expect a number as -2. */
4658 if (lua_type(L, -2) != LUA_TNUMBER) {
4659 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'][] element must be a number. got %s.\n",
4660 appctx->appctx->rule->arg.hlua_rule->fcn.name,
4661 name,
4662 lua_typename(L, lua_type(L, -2)));
4663 WILL_LJMP(lua_error(L));
4664 }
4665 id = lua_tointeger(L, -2);
4666
4667 /* We expect a string as -2. */
4668 if (lua_type(L, -1) != LUA_TSTRING) {
4669 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'][%d] element must be a string. got %s.\n",
4670 appctx->appctx->rule->arg.hlua_rule->fcn.name,
4671 name, id,
4672 lua_typename(L, lua_type(L, -1)));
4673 WILL_LJMP(lua_error(L));
4674 }
4675 value = lua_tolstring(L, -1, &vlen);
4676
4677 /* Simple Protocol checks. */
4678 if (isteqi(ist2(name, nlen), ist("transfer-encoding")))
Christopher Faulet700d9e82020-01-31 12:21:52 +01004679 h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004680 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
4681 struct ist v = ist2(value, vlen);
4682 int ret;
4683
4684 ret = h1_parse_cont_len_header(&h1m, &v);
4685 if (ret < 0) {
4686 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
4687 appctx->appctx->rule->arg.hlua_rule->fcn.name,
4688 name);
4689 WILL_LJMP(lua_error(L));
4690 }
4691 else if (ret == 0)
4692 goto next; /* Skip it */
4693 }
4694
4695 /* Add a new header */
4696 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
4697 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
4698 appctx->appctx->rule->arg.hlua_rule->fcn.name,
4699 name);
4700 WILL_LJMP(lua_error(L));
4701 }
4702 next:
4703 /* Remove the array from the stack, and get next element with a remaining string. */
4704 lua_pop(L, 1);
4705 }
4706
4707 /* Remove the array from the stack, and get next element with a remaining string. */
4708 lua_pop(L, 1);
4709 }
4710
4711 if (h1m.flags & H1_MF_CHNK)
4712 h1m.flags &= ~H1_MF_CLEN;
4713 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
4714 h1m.flags |= H1_MF_XFER_LEN;
4715
4716 /* Uset HTX start-line flags */
4717 if (h1m.flags & H1_MF_XFER_ENC)
4718 flags |= HTX_SL_F_XFER_ENC;
4719 if (h1m.flags & H1_MF_XFER_LEN) {
4720 flags |= HTX_SL_F_XFER_LEN;
4721 if (h1m.flags & H1_MF_CHNK)
4722 flags |= HTX_SL_F_CHNK;
4723 else if (h1m.flags & H1_MF_CLEN)
4724 flags |= HTX_SL_F_CLEN;
4725 if (h1m.body_len == 0)
4726 flags |= HTX_SL_F_BODYLESS;
4727 }
4728 sl->flags |= flags;
4729
4730 /* If we dont have a content-length set, and the HTTP version is 1.1
4731 * and the status code implies the presence of a message body, we must
4732 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004733 * for the keepalive compliance. If the applet announces a transfer-encoding
4734 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004735 */
4736 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
4737 appctx->appctx->ctx.hlua_apphttp.status >= 200 &&
4738 appctx->appctx->ctx.hlua_apphttp.status != 204 &&
4739 appctx->appctx->ctx.hlua_apphttp.status != 304) {
4740 /* Add a new header */
4741 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
4742 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
4743 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
4744 appctx->appctx->rule->arg.hlua_rule->fcn.name);
4745 WILL_LJMP(lua_error(L));
4746 }
4747 }
4748
4749 /* Finalize headers. */
4750 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
4751 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
4752 appctx->appctx->rule->arg.hlua_rule->fcn.name);
4753 WILL_LJMP(lua_error(L));
4754 }
4755
4756 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
4757 b_reset(&res->buf);
4758 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
4759 WILL_LJMP(lua_error(L));
4760 }
4761
4762 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004763 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004764
4765 /* Headers sent, set the flag. */
4766 appctx->appctx->ctx.hlua_apphttp.flags |= APPLET_HDR_SENT;
4767 return 0;
4768
4769}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004770/* We will build the status line and the headers of the HTTP response.
4771 * We will try send at once if its not possible, we give back the hand
4772 * waiting for more room.
4773 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004774__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004775{
4776 struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4777 struct stream_interface *si = appctx->appctx->owner;
4778 struct channel *res = si_ic(si);
4779
4780 if (co_data(res)) {
4781 si_rx_room_blk(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004782 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004783 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004784 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004785}
4786
4787
Christopher Fauleta2097962019-07-15 16:25:33 +02004788__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004789{
Christopher Fauleta2097962019-07-15 16:25:33 +02004790 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004791}
4792
Christopher Fauleta2097962019-07-15 16:25:33 +02004793/*
4794 *
4795 *
4796 * Class HTTP
4797 *
4798 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004799 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004800
4801/* Returns a struct hlua_txn if the stack entry "ud" is
4802 * a class stream, otherwise it throws an error.
4803 */
4804__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004805{
Christopher Fauleta2097962019-07-15 16:25:33 +02004806 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
4807}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004808
Christopher Fauleta2097962019-07-15 16:25:33 +02004809/* This function creates and push in the stack a HTTP object
4810 * according with a current TXN.
4811 */
4812static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
4813{
4814 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004815
Christopher Fauleta2097962019-07-15 16:25:33 +02004816 /* Check stack size. */
4817 if (!lua_checkstack(L, 3))
4818 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004819
Christopher Fauleta2097962019-07-15 16:25:33 +02004820 /* Create the object: obj[0] = userdata.
4821 * Note that the base of the Converters object is the
4822 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004823 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004824 lua_newtable(L);
4825 htxn = lua_newuserdata(L, sizeof(*htxn));
4826 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004827
4828 htxn->s = txn->s;
4829 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02004830 htxn->dir = txn->dir;
4831 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004832
4833 /* Pop a class stream metatable and affect it to the table. */
4834 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
4835 lua_setmetatable(L, -2);
4836
4837 return 1;
4838}
4839
4840/* This function creates ans returns an array of HTTP headers.
4841 * This function does not fails. It is used as wrapper with the
4842 * 2 following functions.
4843 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004844__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004845{
Christopher Fauleta2097962019-07-15 16:25:33 +02004846 struct htx *htx;
4847 int32_t pos;
4848
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004849 /* Create the table. */
4850 lua_newtable(L);
4851
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004852
Christopher Fauleta2097962019-07-15 16:25:33 +02004853 htx = htxbuf(&msg->chn->buf);
4854 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4855 struct htx_blk *blk = htx_get_blk(htx, pos);
4856 enum htx_blk_type type = htx_get_blk_type(blk);
4857 struct ist n, v;
4858 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01004859
Christopher Fauleta2097962019-07-15 16:25:33 +02004860 if (type == HTX_BLK_HDR) {
4861 n = htx_get_blk_name(htx,blk);
4862 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01004863 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004864 else if (type == HTX_BLK_EOH)
4865 break;
4866 else
4867 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01004868
Christopher Fauleta2097962019-07-15 16:25:33 +02004869 /* Check for existing entry:
4870 * assume that the table is on the top of the stack, and
4871 * push the key in the stack, the function lua_gettable()
4872 * perform the lookup.
4873 */
4874 lua_pushlstring(L, n.ptr, n.len);
4875 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01004876
Christopher Fauleta2097962019-07-15 16:25:33 +02004877 switch (lua_type(L, -1)) {
4878 case LUA_TNIL:
4879 /* Table not found, create it. */
4880 lua_pop(L, 1); /* remove the nil value. */
4881 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
4882 lua_newtable(L); /* create and push empty table. */
4883 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
4884 lua_rawseti(L, -2, 0); /* index header value (pop it). */
4885 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01004886 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01004887
Christopher Fauleta2097962019-07-15 16:25:33 +02004888 case LUA_TTABLE:
4889 /* Entry found: push the value in the table. */
4890 len = lua_rawlen(L, -1);
4891 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
4892 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
4893 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
4894 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004895
Christopher Fauleta2097962019-07-15 16:25:33 +02004896 default:
4897 /* Other cases are errors. */
4898 hlua_pusherror(L, "internal error during the parsing of headers.");
4899 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004900 }
4901 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004902 return 1;
4903}
4904
4905__LJMP static int hlua_http_req_get_headers(lua_State *L)
4906{
4907 struct hlua_txn *htxn;
4908
4909 MAY_LJMP(check_args(L, 1, "req_get_headers"));
4910 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4911
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004912 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02004913 WILL_LJMP(lua_error(L));
4914
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004915 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004916}
4917
4918__LJMP static int hlua_http_res_get_headers(lua_State *L)
4919{
4920 struct hlua_txn *htxn;
4921
4922 MAY_LJMP(check_args(L, 1, "res_get_headers"));
4923 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4924
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004925 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02004926 WILL_LJMP(lua_error(L));
4927
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004928 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004929}
4930
4931/* This function replace full header, or just a value in
4932 * the request or in the response. It is a wrapper fir the
4933 * 4 following functions.
4934 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01004935__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004936{
4937 size_t name_len;
4938 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
4939 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
4940 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02004941 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02004942 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004943
Dragan Dosen26743032019-04-30 15:54:36 +02004944 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004945 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
4946
Christopher Fauleta2097962019-07-15 16:25:33 +02004947 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01004948 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02004949 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004950 return 0;
4951}
4952
4953__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
4954{
4955 struct hlua_txn *htxn;
4956
4957 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
4958 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4959
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004960 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02004961 WILL_LJMP(lua_error(L));
4962
Christopher Fauletd1914aa2020-02-24 16:52:46 +01004963 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004964}
4965
4966__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
4967{
4968 struct hlua_txn *htxn;
4969
4970 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
4971 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4972
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004973 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02004974 WILL_LJMP(lua_error(L));
4975
Christopher Fauletd1914aa2020-02-24 16:52:46 +01004976 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004977}
4978
4979__LJMP static int hlua_http_req_rep_val(lua_State *L)
4980{
4981 struct hlua_txn *htxn;
4982
4983 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
4984 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4985
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004986 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02004987 WILL_LJMP(lua_error(L));
4988
Christopher Fauletd1914aa2020-02-24 16:52:46 +01004989 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004990}
4991
4992__LJMP static int hlua_http_res_rep_val(lua_State *L)
4993{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004994 struct hlua_txn *htxn;
4995
4996 MAY_LJMP(check_args(L, 4, "res_rep_val"));
4997 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
4998
Christopher Fauletd8f0e072020-02-25 09:45:51 +01004999 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005000 WILL_LJMP(lua_error(L));
5001
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005002 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005003}
5004
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005005/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005006 * It is a wrapper for the 2 following functions.
5007 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005008__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005009{
5010 size_t len;
5011 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005012 struct htx *htx = htxbuf(&msg->chn->buf);
5013 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005014
Christopher Fauleta2097962019-07-15 16:25:33 +02005015 ctx.blk = NULL;
5016 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5017 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005018 return 0;
5019}
5020
5021__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5022{
5023 struct hlua_txn *htxn;
5024
5025 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5026 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5027
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005028 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005029 WILL_LJMP(lua_error(L));
5030
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005031 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005032}
5033
5034__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5035{
5036 struct hlua_txn *htxn;
5037
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005038 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005039 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5040
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005041 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005042 WILL_LJMP(lua_error(L));
5043
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005044 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005045}
5046
5047/* This function adds an header. It is a wrapper used by
5048 * the 2 following functions.
5049 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005050__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005051{
5052 size_t name_len;
5053 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5054 size_t value_len;
5055 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005056 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005057
Christopher Fauleta2097962019-07-15 16:25:33 +02005058 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5059 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005060 return 0;
5061}
5062
5063__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5064{
5065 struct hlua_txn *htxn;
5066
5067 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5068 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5069
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005070 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005071 WILL_LJMP(lua_error(L));
5072
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005073 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005074}
5075
5076__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5077{
5078 struct hlua_txn *htxn;
5079
5080 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5081 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5082
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005083 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005084 WILL_LJMP(lua_error(L));
5085
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005086 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005087}
5088
5089static int hlua_http_req_set_hdr(lua_State *L)
5090{
5091 struct hlua_txn *htxn;
5092
5093 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5094 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5095
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005096 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005097 WILL_LJMP(lua_error(L));
5098
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005099 hlua_http_del_hdr(L, &htxn->s->txn->req);
5100 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005101}
5102
5103static int hlua_http_res_set_hdr(lua_State *L)
5104{
5105 struct hlua_txn *htxn;
5106
5107 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
5108 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5109
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005110 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005111 WILL_LJMP(lua_error(L));
5112
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005113 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
5114 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005115}
5116
5117/* This function set the method. */
5118static int hlua_http_req_set_meth(lua_State *L)
5119{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005120 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005121 size_t name_len;
5122 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005123
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005124 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005125 WILL_LJMP(lua_error(L));
5126
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005127 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005128 return 1;
5129}
5130
5131/* This function set the method. */
5132static int hlua_http_req_set_path(lua_State *L)
5133{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005134 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005135 size_t name_len;
5136 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02005137
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005138 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005139 WILL_LJMP(lua_error(L));
5140
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005141 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005142 return 1;
5143}
5144
5145/* This function set the query-string. */
5146static int hlua_http_req_set_query(lua_State *L)
5147{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005148 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005149 size_t name_len;
5150 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005151
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005152 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005153 WILL_LJMP(lua_error(L));
5154
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005155 /* Check length. */
5156 if (name_len > trash.size - 1) {
5157 lua_pushboolean(L, 0);
5158 return 1;
5159 }
5160
5161 /* Add the mark question as prefix. */
5162 chunk_reset(&trash);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005163 trash.area[trash.data++] = '?';
5164 memcpy(trash.area + trash.data, name, name_len);
5165 trash.data += name_len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005166
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005167 lua_pushboolean(L,
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005168 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005169 return 1;
5170}
5171
5172/* This function set the uri. */
5173static int hlua_http_req_set_uri(lua_State *L)
5174{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005175 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005176 size_t name_len;
5177 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005178
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005179 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005180 WILL_LJMP(lua_error(L));
5181
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005182 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005183 return 1;
5184}
5185
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005186/* This function set the response code & optionally reason. */
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005187static int hlua_http_res_set_status(lua_State *L)
5188{
5189 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5190 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Faulet96bff762019-12-17 13:46:18 +01005191 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
5192 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005193
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005194 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005195 WILL_LJMP(lua_error(L));
5196
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005197 http_res_set_status(code, reason, htxn->s);
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005198 return 0;
5199}
5200
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005201/*
5202 *
5203 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005204 * Class TXN
5205 *
5206 *
5207 */
5208
5209/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02005210 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005211 */
5212__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
5213{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02005214 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005215}
5216
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005217__LJMP static int hlua_set_var(lua_State *L)
5218{
5219 struct hlua_txn *htxn;
5220 const char *name;
5221 size_t len;
5222 struct sample smp;
5223
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005224 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
5225 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005226
5227 /* It is useles to retrieve the stream, but this function
5228 * runs only in a stream context.
5229 */
5230 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5231 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5232
5233 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01005234 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005235 hlua_lua2smp(L, 3, &smp);
5236
5237 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01005238 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005239
5240 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
5241 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
5242 else
5243 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
5244
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005245 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005246}
5247
Christopher Faulet85d79c92016-11-09 16:54:56 +01005248__LJMP static int hlua_unset_var(lua_State *L)
5249{
5250 struct hlua_txn *htxn;
5251 const char *name;
5252 size_t len;
5253 struct sample smp;
5254
5255 MAY_LJMP(check_args(L, 2, "unset_var"));
5256
5257 /* It is useles to retrieve the stream, but this function
5258 * runs only in a stream context.
5259 */
5260 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5261 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5262
5263 /* Unset the variable. */
5264 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005265 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
5266 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01005267}
5268
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005269__LJMP static int hlua_get_var(lua_State *L)
5270{
5271 struct hlua_txn *htxn;
5272 const char *name;
5273 size_t len;
5274 struct sample smp;
5275
5276 MAY_LJMP(check_args(L, 2, "get_var"));
5277
5278 /* It is useles to retrieve the stream, but this function
5279 * runs only in a stream context.
5280 */
5281 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5282 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5283
Willy Tarreau7560dd42016-03-10 16:28:58 +01005284 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreau6204cd92016-03-10 16:33:04 +01005285 if (!vars_get_by_name(name, len, &smp)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005286 lua_pushnil(L);
5287 return 1;
5288 }
5289
5290 return hlua_smp2lua(L, &smp);
5291}
5292
Willy Tarreau59551662015-03-10 14:23:13 +01005293__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005294{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005295 struct hlua *hlua;
5296
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005297 MAY_LJMP(check_args(L, 2, "set_priv"));
5298
Willy Tarreau87b09662015-04-03 00:22:06 +02005299 /* It is useles to retrieve the stream, but this function
5300 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005301 */
5302 MAY_LJMP(hlua_checktxn(L, 1));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005303 hlua = hlua_gethlua(L);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005304
5305 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005306 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005307
5308 /* Get and store new value. */
5309 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5310 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5311
5312 return 0;
5313}
5314
Willy Tarreau59551662015-03-10 14:23:13 +01005315__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005316{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005317 struct hlua *hlua;
5318
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005319 MAY_LJMP(check_args(L, 1, "get_priv"));
5320
Willy Tarreau87b09662015-04-03 00:22:06 +02005321 /* It is useles to retrieve the stream, but this function
5322 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005323 */
5324 MAY_LJMP(hlua_checktxn(L, 1));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005325 hlua = hlua_gethlua(L);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005326
5327 /* Push configuration index in the stack. */
5328 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5329
5330 return 1;
5331}
5332
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005333/* Create stack entry containing a class TXN. This function
5334 * return 0 if the stack does not contains free slots,
5335 * otherwise it returns 1.
5336 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005337static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005338{
Willy Tarreaude491382015-04-06 11:04:28 +02005339 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005340
5341 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005342 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005343 return 0;
5344
5345 /* NOTE: The allocation never fails. The failure
5346 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005347 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005348 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005349 /* Create the object: obj[0] = userdata. */
5350 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02005351 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005352 lua_rawseti(L, -2, 0);
5353
Willy Tarreaude491382015-04-06 11:04:28 +02005354 htxn->s = s;
5355 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01005356 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005357 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005358
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005359 /* Create the "f" field that contains a list of fetches. */
5360 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005361 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005362 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005363 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005364
5365 /* Create the "sf" field that contains a list of stringsafe fetches. */
5366 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005367 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005368 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005369 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005370
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005371 /* Create the "c" field that contains a list of converters. */
5372 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02005373 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005374 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005375 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005376
5377 /* Create the "sc" field that contains a list of stringsafe converters. */
5378 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01005379 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005380 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005381 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005382
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005383 /* Create the "req" field that contains the request channel object. */
5384 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005385 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005386 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005387 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005388
5389 /* Create the "res" field that contains the response channel object. */
5390 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005391 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005392 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005393 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005394
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005395 /* Creates the HTTP object is the current proxy allows http. */
5396 lua_pushstring(L, "http");
5397 if (p->mode == PR_MODE_HTTP) {
Willy Tarreaude491382015-04-06 11:04:28 +02005398 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005399 return 0;
5400 }
5401 else
5402 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005403 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005404
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005405 /* Pop a class sesison metatable and affect it to the userdata. */
5406 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
5407 lua_setmetatable(L, -2);
5408
5409 return 1;
5410}
5411
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005412__LJMP static int hlua_txn_deflog(lua_State *L)
5413{
5414 const char *msg;
5415 struct hlua_txn *htxn;
5416
5417 MAY_LJMP(check_args(L, 2, "deflog"));
5418 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5419 msg = MAY_LJMP(luaL_checkstring(L, 2));
5420
5421 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
5422 return 0;
5423}
5424
5425__LJMP static int hlua_txn_log(lua_State *L)
5426{
5427 int level;
5428 const char *msg;
5429 struct hlua_txn *htxn;
5430
5431 MAY_LJMP(check_args(L, 3, "log"));
5432 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5433 level = MAY_LJMP(luaL_checkinteger(L, 2));
5434 msg = MAY_LJMP(luaL_checkstring(L, 3));
5435
5436 if (level < 0 || level >= NB_LOG_LEVELS)
5437 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
5438
5439 hlua_sendlog(htxn->s->be, level, msg);
5440 return 0;
5441}
5442
5443__LJMP static int hlua_txn_log_debug(lua_State *L)
5444{
5445 const char *msg;
5446 struct hlua_txn *htxn;
5447
5448 MAY_LJMP(check_args(L, 2, "Debug"));
5449 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5450 msg = MAY_LJMP(luaL_checkstring(L, 2));
5451 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
5452 return 0;
5453}
5454
5455__LJMP static int hlua_txn_log_info(lua_State *L)
5456{
5457 const char *msg;
5458 struct hlua_txn *htxn;
5459
5460 MAY_LJMP(check_args(L, 2, "Info"));
5461 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5462 msg = MAY_LJMP(luaL_checkstring(L, 2));
5463 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
5464 return 0;
5465}
5466
5467__LJMP static int hlua_txn_log_warning(lua_State *L)
5468{
5469 const char *msg;
5470 struct hlua_txn *htxn;
5471
5472 MAY_LJMP(check_args(L, 2, "Warning"));
5473 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5474 msg = MAY_LJMP(luaL_checkstring(L, 2));
5475 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
5476 return 0;
5477}
5478
5479__LJMP static int hlua_txn_log_alert(lua_State *L)
5480{
5481 const char *msg;
5482 struct hlua_txn *htxn;
5483
5484 MAY_LJMP(check_args(L, 2, "Alert"));
5485 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5486 msg = MAY_LJMP(luaL_checkstring(L, 2));
5487 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
5488 return 0;
5489}
5490
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005491__LJMP static int hlua_txn_set_loglevel(lua_State *L)
5492{
5493 struct hlua_txn *htxn;
5494 int ll;
5495
5496 MAY_LJMP(check_args(L, 2, "set_loglevel"));
5497 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5498 ll = MAY_LJMP(luaL_checkinteger(L, 2));
5499
5500 if (ll < 0 || ll > 7)
5501 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
5502
5503 htxn->s->logs.level = ll;
5504 return 0;
5505}
5506
5507__LJMP static int hlua_txn_set_tos(lua_State *L)
5508{
5509 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005510 int tos;
5511
5512 MAY_LJMP(check_args(L, 2, "set_tos"));
5513 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5514 tos = MAY_LJMP(luaL_checkinteger(L, 2));
5515
Willy Tarreau1a18b542018-12-11 16:37:42 +01005516 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005517 return 0;
5518}
5519
5520__LJMP static int hlua_txn_set_mark(lua_State *L)
5521{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005522 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005523 int mark;
5524
5525 MAY_LJMP(check_args(L, 2, "set_mark"));
5526 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5527 mark = MAY_LJMP(luaL_checkinteger(L, 2));
5528
Lukas Tribus579e3e32019-08-11 18:03:45 +02005529 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005530 return 0;
5531}
5532
Patrick Hemmer268a7072018-05-11 12:52:31 -04005533__LJMP static int hlua_txn_set_priority_class(lua_State *L)
5534{
5535 struct hlua_txn *htxn;
5536
5537 MAY_LJMP(check_args(L, 2, "set_priority_class"));
5538 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5539 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
5540 return 0;
5541}
5542
5543__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
5544{
5545 struct hlua_txn *htxn;
5546
5547 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
5548 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5549 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
5550 return 0;
5551}
5552
Christopher Faulet700d9e82020-01-31 12:21:52 +01005553/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005554 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01005555 * message and terminate the transaction. It returns 1 on success and 0 on
5556 * error. The Reply must be on top of the stack.
5557 */
5558__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
5559{
5560 struct htx *htx;
5561 struct htx_sl *sl;
5562 struct h1m h1m;
5563 const char *status, *reason, *body;
5564 size_t status_len, reason_len, body_len;
5565 int ret, code, flags;
5566
5567 code = 200;
5568 status = "200";
5569 status_len = 3;
5570 ret = lua_getfield(L, -1, "status");
5571 if (ret == LUA_TNUMBER) {
5572 code = lua_tointeger(L, -1);
5573 status = lua_tolstring(L, -1, &status_len);
5574 }
5575 lua_pop(L, 1);
5576
5577 reason = http_get_reason(code);
5578 reason_len = strlen(reason);
5579 ret = lua_getfield(L, -1, "reason");
5580 if (ret == LUA_TSTRING)
5581 reason = lua_tolstring(L, -1, &reason_len);
5582 lua_pop(L, 1);
5583
5584 body = NULL;
5585 body_len = 0;
5586 ret = lua_getfield(L, -1, "body");
5587 if (ret == LUA_TSTRING)
5588 body = lua_tolstring(L, -1, &body_len);
5589 lua_pop(L, 1);
5590
5591 /* Prepare the response before inserting the headers */
5592 h1m_init_res(&h1m);
5593 htx = htx_from_buf(&s->res.buf);
5594 channel_htx_truncate(&s->res, htx);
5595 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
5596 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5597 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
5598 ist2(status, status_len), ist2(reason, reason_len));
5599 }
5600 else {
5601 flags = HTX_SL_F_IS_RESP;
5602 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
5603 ist2(status, status_len), ist2(reason, reason_len));
5604 }
5605 if (!sl)
5606 goto fail;
5607 sl->info.res.status = code;
5608
5609 /* Push in the stack the "headers" entry. */
5610 ret = lua_getfield(L, -1, "headers");
5611 if (ret != LUA_TTABLE)
5612 goto skip_headers;
5613
5614 lua_pushnil(L);
5615 while (lua_next(L, -2) != 0) {
5616 struct ist name, value;
5617 const char *n, *v;
5618 size_t nlen, vlen;
5619
5620 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
5621 /* Skip element if the key is not a string or if the value is not a table */
5622 goto next_hdr;
5623 }
5624
5625 n = lua_tolstring(L, -2, &nlen);
5626 name = ist2(n, nlen);
5627 if (isteqi(name, ist("content-length"))) {
5628 /* Always skip content-length header. It will be added
5629 * later with the correct len
5630 */
5631 goto next_hdr;
5632 }
5633
5634 /* Loop on header's values */
5635 lua_pushnil(L);
5636 while (lua_next(L, -2)) {
5637 if (!lua_isstring(L, -1)) {
5638 /* Skip the value if it is not a string */
5639 goto next_value;
5640 }
5641
5642 v = lua_tolstring(L, -1, &vlen);
5643 value = ist2(v, vlen);
5644
5645 if (isteqi(name, ist("transfer-encoding")))
5646 h1_parse_xfer_enc_header(&h1m, value);
5647 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
5648 goto fail;
5649
5650 next_value:
5651 lua_pop(L, 1);
5652 }
5653
5654 next_hdr:
5655 lua_pop(L, 1);
5656 }
5657 skip_headers:
5658 lua_pop(L, 1);
5659
5660 /* Update h1m flags: CLEN is set if CHNK is not present */
5661 if (!(h1m.flags & H1_MF_CHNK)) {
5662 const char *clen = ultoa(body_len);
5663
5664 h1m.flags |= H1_MF_CLEN;
5665 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
5666 goto fail;
5667 }
5668 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5669 h1m.flags |= H1_MF_XFER_LEN;
5670
5671 /* Update HTX start-line flags */
5672 if (h1m.flags & H1_MF_XFER_ENC)
5673 flags |= HTX_SL_F_XFER_ENC;
5674 if (h1m.flags & H1_MF_XFER_LEN) {
5675 flags |= HTX_SL_F_XFER_LEN;
5676 if (h1m.flags & H1_MF_CHNK)
5677 flags |= HTX_SL_F_CHNK;
5678 else if (h1m.flags & H1_MF_CLEN)
5679 flags |= HTX_SL_F_CLEN;
5680 if (h1m.body_len == 0)
5681 flags |= HTX_SL_F_BODYLESS;
5682 }
5683 sl->flags |= flags;
5684
5685
5686 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
5687 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))) ||
5688 !htx_add_endof(htx, HTX_BLK_EOM))
5689 goto fail;
5690
5691 /* Now, forward the response and terminate the transaction */
5692 s->txn->status = code;
5693 htx_to_buf(htx, &s->res.buf);
5694 if (!http_forward_proxy_resp(s, 1))
5695 goto fail;
5696
5697 return 1;
5698
5699 fail:
5700 channel_htx_truncate(&s->res, htx);
5701 return 0;
5702}
5703
5704/* Terminate a transaction if called from a lua action. For TCP streams,
5705 * processing is just aborted. Nothing is returned to the client and all
5706 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
5707 * is forwarded to the client before terminating the transaction. On success,
5708 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
5709 * with ACT_RET_ERR code. If this function is not called from a lua action, it
5710 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005711 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005712__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005713{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02005714 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01005715 struct stream *s;
5716 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005717
Willy Tarreaub2ccb562015-04-06 11:11:15 +02005718 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005719
Christopher Faulet700d9e82020-01-31 12:21:52 +01005720 /* If the flags NOTERM is set, we cannot terminate the session, so we
5721 * just end the execution of the current lua code. */
5722 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005723 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005724
Christopher Faulet700d9e82020-01-31 12:21:52 +01005725 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005726 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01005727 struct channel *req = &s->req;
5728 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01005729
Christopher Faulet700d9e82020-01-31 12:21:52 +01005730 channel_auto_read(req);
5731 channel_abort(req);
5732 channel_auto_close(req);
5733 channel_erase(req);
5734
5735 res->wex = tick_add_ifset(now_ms, res->wto);
5736 channel_auto_read(res);
5737 channel_auto_close(res);
5738 channel_shutr_now(res);
5739
5740 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
5741 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005742 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02005743
Christopher Faulet700d9e82020-01-31 12:21:52 +01005744 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
5745 /* No reply or invalid reply */
5746 s->txn->status = 0;
5747 http_reply_and_close(s, 0, NULL);
5748 }
5749 else {
5750 /* Remove extra args to have the reply on top of the stack */
5751 if (lua_gettop(L) > 2)
5752 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005753
Christopher Faulet700d9e82020-01-31 12:21:52 +01005754 if (!hlua_txn_forward_reply(L, s)) {
5755 if (!(s->flags & SF_ERR_MASK))
5756 s->flags |= SF_ERR_PRXCOND;
5757 lua_pushinteger(L, ACT_RET_ERR);
5758 WILL_LJMP(hlua_done(L));
5759 return 0; /* Never reached */
5760 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02005761 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005762
Christopher Faulet700d9e82020-01-31 12:21:52 +01005763 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
5764 if (htxn->dir == SMP_OPT_DIR_REQ) {
5765 /* let's log the request time */
5766 s->logs.tv_request = now;
5767 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
5768 _HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1);
5769 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005770
Christopher Faulet700d9e82020-01-31 12:21:52 +01005771 done:
5772 if (!(s->flags & SF_ERR_MASK))
5773 s->flags |= SF_ERR_LOCAL;
5774 if (!(s->flags & SF_FINST_MASK))
5775 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005776
Christopher Faulet4ad73102020-03-05 11:07:31 +01005777 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005778 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005779 return 0;
5780}
5781
Christopher Faulet700d9e82020-01-31 12:21:52 +01005782/*
5783 *
5784 *
5785 * Class REPLY
5786 *
5787 *
5788 */
5789
5790/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
5791 * free slots, the function fails and returns 0;
5792 */
5793static int hlua_txn_reply_new(lua_State *L)
5794{
5795 struct hlua_txn *htxn;
5796 const char *reason, *body = NULL;
5797 int ret, status;
5798
5799 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005800 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01005801 hlua_pusherror(L, "txn object is not an HTTP transaction.");
5802 WILL_LJMP(lua_error(L));
5803 }
5804
5805 /* Default value */
5806 status = 200;
5807 reason = http_get_reason(status);
5808
5809 if (lua_istable(L, 2)) {
5810 /* load status and reason from the table argument at index 2 */
5811 ret = lua_getfield(L, 2, "status");
5812 if (ret == LUA_TNIL)
5813 goto reason;
5814 else if (ret != LUA_TNUMBER) {
5815 /* invalid status: ignore the reason */
5816 goto body;
5817 }
5818 status = lua_tointeger(L, -1);
5819
5820 reason:
5821 lua_pop(L, 1); /* restore the stack: remove status */
5822 ret = lua_getfield(L, 2, "reason");
5823 if (ret == LUA_TSTRING)
5824 reason = lua_tostring(L, -1);
5825
5826 body:
5827 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
5828 ret = lua_getfield(L, 2, "body");
5829 if (ret == LUA_TSTRING)
5830 body = lua_tostring(L, -1);
5831 lua_pop(L, 1); /* restore the stack: remove body */
5832 }
5833
5834 /* Create the Reply table */
5835 lua_newtable(L);
5836
5837 /* Add status element */
5838 lua_pushstring(L, "status");
5839 lua_pushinteger(L, status);
5840 lua_settable(L, -3);
5841
5842 /* Add reason element */
5843 reason = http_get_reason(status);
5844 lua_pushstring(L, "reason");
5845 lua_pushstring(L, reason);
5846 lua_settable(L, -3);
5847
5848 /* Add body element, nil if undefined */
5849 lua_pushstring(L, "body");
5850 if (body)
5851 lua_pushstring(L, body);
5852 else
5853 lua_pushnil(L);
5854 lua_settable(L, -3);
5855
5856 /* Add headers element */
5857 lua_pushstring(L, "headers");
5858 lua_newtable(L);
5859
5860 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
5861 if (lua_istable(L, 2)) {
5862 /* load headers from the table argument at index 2. If it is a table, copy it. */
5863 ret = lua_getfield(L, 2, "headers");
5864 if (ret == LUA_TTABLE) {
5865 /* stack: [ ... <headers:table>, <table> ] */
5866 lua_pushnil(L);
5867 while (lua_next(L, -2) != 0) {
5868 /* stack: [ ... <headers:table>, <table>, k, v] */
5869 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
5870 /* invalid value type, skip it */
5871 lua_pop(L, 1);
5872 continue;
5873 }
5874
5875
5876 /* Duplicate the key and swap it with the value. */
5877 lua_pushvalue(L, -2);
5878 lua_insert(L, -2);
5879 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
5880
5881 lua_newtable(L);
5882 lua_insert(L, -2);
5883 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
5884
5885 if (lua_isstring(L, -1)) {
5886 /* push the value in the inner table */
5887 lua_rawseti(L, -2, 1);
5888 }
5889 else { /* table */
5890 lua_pushnil(L);
5891 while (lua_next(L, -2) != 0) {
5892 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
5893 if (!lua_isstring(L, -1)) {
5894 /* invalid value type, skip it*/
5895 lua_pop(L, 1);
5896 continue;
5897 }
5898 /* push the value in the inner table */
5899 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
5900 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
5901 }
5902 lua_pop(L, 1);
5903 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
5904 }
5905
5906 /* push (k,v) on the stack in the headers table:
5907 * stack: [ ... <headers:table>, <table>, k, k, v ]
5908 */
5909 lua_settable(L, -5);
5910 /* stack: [ ... <headers:table>, <table>, k ] */
5911 }
5912 }
5913 lua_pop(L, 1);
5914 }
5915 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
5916 lua_settable(L, -3);
5917 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
5918
5919 /* Pop a class sesison metatable and affect it to the userdata. */
5920 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
5921 lua_setmetatable(L, -2);
5922 return 1;
5923}
5924
5925/* Set the reply status code, and optionally the reason. If no reason is
5926 * provided, the default one corresponding to the status code is used.
5927 */
5928__LJMP static int hlua_txn_reply_set_status(lua_State *L)
5929{
5930 int status = MAY_LJMP(luaL_checkinteger(L, 2));
5931 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
5932
5933 /* First argument (self) must be a table */
5934 luaL_checktype(L, 1, LUA_TTABLE);
5935
5936 if (status < 100 || status > 599) {
5937 lua_pushboolean(L, 0);
5938 return 1;
5939 }
5940 if (!reason)
5941 reason = http_get_reason(status);
5942
5943 lua_pushinteger(L, status);
5944 lua_setfield(L, 1, "status");
5945
5946 lua_pushstring(L, reason);
5947 lua_setfield(L, 1, "reason");
5948
5949 lua_pushboolean(L, 1);
5950 return 1;
5951}
5952
5953/* Add a header into the reply object. Each header name is associated to an
5954 * array of values in the "headers" table. If the header name is not found, a
5955 * new entry is created.
5956 */
5957__LJMP static int hlua_txn_reply_add_header(lua_State *L)
5958{
5959 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
5960 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
5961 int ret;
5962
5963 /* First argument (self) must be a table */
5964 luaL_checktype(L, 1, LUA_TTABLE);
5965
5966 /* Push in the stack the "headers" entry. */
5967 ret = lua_getfield(L, 1, "headers");
5968 if (ret != LUA_TTABLE) {
5969 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
5970 WILL_LJMP(lua_error(L));
5971 }
5972
5973 /* check if the header is already registered. If not, register it. */
5974 ret = lua_getfield(L, -1, name);
5975 if (ret == LUA_TNIL) {
5976 /* Entry not found. */
5977 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
5978
5979 /* Insert the new header name in the array in the top of the stack.
5980 * It left the new array in the top of the stack.
5981 */
5982 lua_newtable(L);
5983 lua_pushstring(L, name);
5984 lua_pushvalue(L, -2);
5985 lua_settable(L, -4);
5986 }
5987 else if (ret != LUA_TTABLE) {
5988 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
5989 WILL_LJMP(lua_error(L));
5990 }
5991
5992 /* Now the top od thestack is an array of values. We push
5993 * the header value as new entry.
5994 */
5995 lua_pushstring(L, value);
5996 ret = lua_rawlen(L, -2);
5997 lua_rawseti(L, -2, ret + 1);
5998
5999 lua_pushboolean(L, 1);
6000 return 1;
6001}
6002
6003/* Remove all occurrences of a given header name. */
6004__LJMP static int hlua_txn_reply_del_header(lua_State *L)
6005{
6006 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6007 int ret;
6008
6009 /* First argument (self) must be a table */
6010 luaL_checktype(L, 1, LUA_TTABLE);
6011
6012 /* Push in the stack the "headers" entry. */
6013 ret = lua_getfield(L, 1, "headers");
6014 if (ret != LUA_TTABLE) {
6015 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
6016 WILL_LJMP(lua_error(L));
6017 }
6018
6019 lua_pushstring(L, name);
6020 lua_pushnil(L);
6021 lua_settable(L, -3);
6022
6023 lua_pushboolean(L, 1);
6024 return 1;
6025}
6026
6027/* Set the reply's body. Overwrite any existing entry. */
6028__LJMP static int hlua_txn_reply_set_body(lua_State *L)
6029{
6030 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
6031
6032 /* First argument (self) must be a table */
6033 luaL_checktype(L, 1, LUA_TTABLE);
6034
6035 lua_pushstring(L, payload);
6036 lua_setfield(L, 1, "body");
6037
6038 lua_pushboolean(L, 1);
6039 return 1;
6040}
6041
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01006042__LJMP static int hlua_log(lua_State *L)
6043{
6044 int level;
6045 const char *msg;
6046
6047 MAY_LJMP(check_args(L, 2, "log"));
6048 level = MAY_LJMP(luaL_checkinteger(L, 1));
6049 msg = MAY_LJMP(luaL_checkstring(L, 2));
6050
6051 if (level < 0 || level >= NB_LOG_LEVELS)
6052 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
6053
6054 hlua_sendlog(NULL, level, msg);
6055 return 0;
6056}
6057
6058__LJMP static int hlua_log_debug(lua_State *L)
6059{
6060 const char *msg;
6061
6062 MAY_LJMP(check_args(L, 1, "debug"));
6063 msg = MAY_LJMP(luaL_checkstring(L, 1));
6064 hlua_sendlog(NULL, LOG_DEBUG, msg);
6065 return 0;
6066}
6067
6068__LJMP static int hlua_log_info(lua_State *L)
6069{
6070 const char *msg;
6071
6072 MAY_LJMP(check_args(L, 1, "info"));
6073 msg = MAY_LJMP(luaL_checkstring(L, 1));
6074 hlua_sendlog(NULL, LOG_INFO, msg);
6075 return 0;
6076}
6077
6078__LJMP static int hlua_log_warning(lua_State *L)
6079{
6080 const char *msg;
6081
6082 MAY_LJMP(check_args(L, 1, "warning"));
6083 msg = MAY_LJMP(luaL_checkstring(L, 1));
6084 hlua_sendlog(NULL, LOG_WARNING, msg);
6085 return 0;
6086}
6087
6088__LJMP static int hlua_log_alert(lua_State *L)
6089{
6090 const char *msg;
6091
6092 MAY_LJMP(check_args(L, 1, "alert"));
6093 msg = MAY_LJMP(luaL_checkstring(L, 1));
6094 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006095 return 0;
6096}
6097
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006098__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006099{
6100 int wakeup_ms = lua_tointeger(L, -1);
6101 if (now_ms < wakeup_ms)
Willy Tarreau9635e032018-10-16 17:52:55 +02006102 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006103 return 0;
6104}
6105
6106__LJMP static int hlua_sleep(lua_State *L)
6107{
6108 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006109 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006110
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006111 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006112
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006113 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006114 wakeup_ms = tick_add(now_ms, delay);
6115 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006116
Willy Tarreau9635e032018-10-16 17:52:55 +02006117 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006118 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006119}
6120
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006121__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006122{
6123 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006124 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006125
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006126 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006127
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006128 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006129 wakeup_ms = tick_add(now_ms, delay);
6130 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006131
Willy Tarreau9635e032018-10-16 17:52:55 +02006132 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006133 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006134}
6135
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006136/* This functionis an LUA binding. it permits to give back
6137 * the hand at the HAProxy scheduler. It is used when the
6138 * LUA processing consumes a lot of time.
6139 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006140__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006141{
6142 return 0;
6143}
6144
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006145__LJMP static int hlua_yield(lua_State *L)
6146{
Willy Tarreau9635e032018-10-16 17:52:55 +02006147 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006148 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006149}
6150
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006151/* This function change the nice of the currently executed
6152 * task. It is used set low or high priority at the current
6153 * task.
6154 */
Willy Tarreau59551662015-03-10 14:23:13 +01006155__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006156{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006157 struct hlua *hlua;
6158 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006159
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006160 MAY_LJMP(check_args(L, 1, "set_nice"));
6161 hlua = hlua_gethlua(L);
6162 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006163
6164 /* If he task is not set, I'm in a start mode. */
6165 if (!hlua || !hlua->task)
6166 return 0;
6167
6168 if (nice < -1024)
6169 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006170 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006171 nice = 1024;
6172
6173 hlua->task->nice = nice;
6174 return 0;
6175}
6176
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006177/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006178 * HAProxy task subsystem when the task is awaked. The LUA runtime can
6179 * return an E_AGAIN signal, the emmiter of this signal must set a
6180 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006181 *
6182 * Task wrapper are longjmp safe because the only one Lua code
6183 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006184 */
Willy Tarreau60409db2019-08-21 14:14:50 +02006185struct task *hlua_process_task(struct task *task, void *context, unsigned short state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006186{
Olivier Houchard9f6af332018-05-25 14:04:04 +02006187 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006188 enum hlua_exec status;
6189
Christopher Faulet5bc99722018-04-25 10:34:45 +02006190 if (task->thread_mask == MAX_THREADS_MASK)
6191 task_set_affinity(task, tid_bit);
6192
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006193 /* If it is the first call to the task, we must initialize the
6194 * execution timeouts.
6195 */
6196 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02006197 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006198
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006199 /* Execute the Lua code. */
6200 status = hlua_ctx_resume(hlua, 1);
6201
6202 switch (status) {
6203 /* finished or yield */
6204 case HLUA_E_OK:
6205 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006206 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02006207 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006208 break;
6209
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01006210 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01006211 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02006212 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006213 break;
6214
6215 /* finished with error. */
6216 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006217 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006218 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006219 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006220 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006221 break;
6222
6223 case HLUA_E_ERR:
6224 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006225 SEND_ERR(NULL, "Lua task: unknown error.\n");
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006226 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006227 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006228 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006229 break;
6230 }
Emeric Brun253e53e2017-10-17 18:58:40 +02006231 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006232}
6233
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006234/* This function is an LUA binding that register LUA function to be
6235 * executed after the HAProxy configuration parsing and before the
6236 * HAProxy scheduler starts. This function expect only one LUA
6237 * argument that is a function. This function returns nothing, but
6238 * throws if an error is encountered.
6239 */
6240__LJMP static int hlua_register_init(lua_State *L)
6241{
6242 struct hlua_init_function *init;
6243 int ref;
6244
6245 MAY_LJMP(check_args(L, 1, "register_init"));
6246
6247 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6248
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006249 init = calloc(1, sizeof(*init));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006250 if (!init)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006251 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006252
6253 init->function_ref = ref;
6254 LIST_ADDQ(&hlua_init_functions, &init->l);
6255 return 0;
6256}
6257
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006258/* This functio is an LUA binding. It permits to register a task
6259 * executed in parallel of the main HAroxy activity. The task is
6260 * created and it is set in the HAProxy scheduler. It can be called
6261 * from the "init" section, "post init" or during the runtime.
6262 *
6263 * Lua prototype:
6264 *
6265 * <none> core.register_task(<function>)
6266 */
6267static int hlua_register_task(lua_State *L)
6268{
6269 struct hlua *hlua;
6270 struct task *task;
6271 int ref;
6272
6273 MAY_LJMP(check_args(L, 1, "register_task"));
6274
6275 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6276
Willy Tarreaubafbe012017-11-24 17:34:44 +01006277 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006278 if (!hlua)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006279 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006280
Emeric Brunc60def82017-09-27 14:59:38 +02006281 task = task_new(MAX_THREADS_MASK);
Willy Tarreaue09101e2018-10-16 17:37:12 +02006282 if (!task)
6283 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6284
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006285 task->context = hlua;
6286 task->process = hlua_process_task;
6287
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01006288 if (!hlua_ctx_init(hlua, task, 1))
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006289 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006290
6291 /* Restore the function in the stack. */
6292 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref);
6293 hlua->nargs = 0;
6294
6295 /* Schedule task. */
6296 task_schedule(task, now_ms);
6297
6298 return 0;
6299}
6300
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006301/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
6302 * doesn't allow "yield" functions because the HAProxy engine cannot
6303 * resume converters.
6304 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006305static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006306{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006307 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006308 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006309 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006310
Willy Tarreaube508f12016-03-10 11:47:01 +01006311 if (!stream)
6312 return 0;
6313
Willy Tarreau87b09662015-04-03 00:22:06 +02006314 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006315 * Lua context can be not initialized. This behavior
6316 * permits to save performances because a systematic
6317 * Lua initialization cause 5% performances loss.
6318 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006319 if (!stream->hlua) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01006320 stream->hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006321 if (!stream->hlua) {
6322 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6323 return 0;
6324 }
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01006325 if (!hlua_ctx_init(stream->hlua, stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006326 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6327 return 0;
6328 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006329 }
6330
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006331 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006332 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006333
6334 /* The following Lua calls can fail. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006335 if (!SET_SAFE_LJMP(stream->hlua->T)) {
6336 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6337 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006338 else
6339 error = "critical error";
6340 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006341 return 0;
6342 }
6343
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006344 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006345 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006346 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006347 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006348 return 0;
6349 }
6350
6351 /* Restore the function in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006352 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006353
6354 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006355 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006356 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006357 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006358 return 0;
6359 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006360 hlua_smp2lua(stream->hlua->T, smp);
6361 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006362
6363 /* push keywords in the stack. */
6364 if (arg_p) {
6365 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006366 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006367 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006368 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006369 return 0;
6370 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006371 hlua_arg2lua(stream->hlua->T, arg_p);
6372 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006373 }
6374 }
6375
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006376 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006377 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006378
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006379 /* At this point the execution is safe. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006380 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006381 }
6382
6383 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006384 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006385 /* finished. */
6386 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006387 /* If the stack is empty, the function fails. */
6388 if (lua_gettop(stream->hlua->T) <= 0)
6389 return 0;
6390
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006391 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006392 hlua_lua2smp(stream->hlua->T, -1, smp);
6393 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006394 return 1;
6395
6396 /* yield. */
6397 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006398 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006399 return 0;
6400
6401 /* finished with error. */
6402 case HLUA_E_ERRMSG:
6403 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006404 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006405 fcn->name, lua_tostring(stream->hlua->T, -1));
6406 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006407 return 0;
6408
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006409 case HLUA_E_ETMOUT:
6410 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
6411 return 0;
6412
6413 case HLUA_E_NOMEM:
6414 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
6415 return 0;
6416
6417 case HLUA_E_YIELD:
6418 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
6419 return 0;
6420
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006421 case HLUA_E_ERR:
6422 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006423 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006424 /* fall through */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006425
6426 default:
6427 return 0;
6428 }
6429}
6430
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006431/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
6432 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01006433 * resume sample-fetches. This function will be called by the sample
6434 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006435 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02006436static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
6437 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006438{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006439 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006440 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006441 const char *error;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006442 unsigned int hflags = HLUA_TXN_NOTERM;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006443
Willy Tarreaube508f12016-03-10 11:47:01 +01006444 if (!stream)
6445 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01006446
Willy Tarreau87b09662015-04-03 00:22:06 +02006447 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006448 * Lua context can be not initialized. This behavior
6449 * permits to save performances because a systematic
6450 * Lua initialization cause 5% performances loss.
6451 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006452 if (!stream->hlua) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01006453 stream->hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006454 if (!stream->hlua) {
6455 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6456 return 0;
6457 }
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01006458 if (!hlua_ctx_init(stream->hlua, stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006459 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6460 return 0;
6461 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006462 }
6463
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006464 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006465 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006466
6467 /* The following Lua calls can fail. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006468 if (!SET_SAFE_LJMP(stream->hlua->T)) {
6469 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6470 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006471 else
6472 error = "critical error";
6473 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006474 return 0;
6475 }
6476
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006477 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006478 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006479 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006480 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006481 return 0;
6482 }
6483
6484 /* Restore the function in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006485 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006486
6487 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006488 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006489 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006490 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006491 return 0;
6492 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006493 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006494
6495 /* push keywords in the stack. */
6496 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
6497 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006498 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006499 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006500 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006501 return 0;
6502 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006503 hlua_arg2lua(stream->hlua->T, arg_p);
6504 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006505 }
6506
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006507 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006508 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006509
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006510 /* At this point the execution is safe. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006511 RESET_SAFE_LJMP(stream->hlua->T);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006512 }
6513
6514 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006515 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006516 /* finished. */
6517 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006518 /* If the stack is empty, the function fails. */
6519 if (lua_gettop(stream->hlua->T) <= 0)
6520 return 0;
6521
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006522 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006523 hlua_lua2smp(stream->hlua->T, -1, smp);
6524 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006525
6526 /* Set the end of execution flag. */
6527 smp->flags &= ~SMP_F_MAY_CHANGE;
6528 return 1;
6529
6530 /* yield. */
6531 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006532 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006533 return 0;
6534
6535 /* finished with error. */
6536 case HLUA_E_ERRMSG:
6537 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006538 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006539 fcn->name, lua_tostring(stream->hlua->T, -1));
6540 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006541 return 0;
6542
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006543 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006544 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
6545 return 0;
6546
6547 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006548 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
6549 return 0;
6550
6551 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006552 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
6553 return 0;
6554
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006555 case HLUA_E_ERR:
6556 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006557 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006558 /* fall through */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006559
6560 default:
6561 return 0;
6562 }
6563}
6564
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006565/* This function is an LUA binding used for registering
6566 * "sample-conv" functions. It expects a converter name used
6567 * in the haproxy configuration file, and an LUA function.
6568 */
6569__LJMP static int hlua_register_converters(lua_State *L)
6570{
6571 struct sample_conv_kw_list *sck;
6572 const char *name;
6573 int ref;
6574 int len;
6575 struct hlua_function *fcn;
Thierry Fournier04cbfd72020-11-28 20:41:07 +01006576 struct sample_conv *sc;
6577 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006578
6579 MAY_LJMP(check_args(L, 2, "register_converters"));
6580
6581 /* First argument : converter name. */
6582 name = MAY_LJMP(luaL_checkstring(L, 1));
6583
6584 /* Second argument : lua function. */
6585 ref = MAY_LJMP(hlua_checkfunction(L, 2));
6586
Thierry Fournier04cbfd72020-11-28 20:41:07 +01006587 /* Check if the converter is already registered */
6588 trash = get_trash_chunk();
6589 chunk_printf(trash, "lua.%s", name);
6590 sc = find_sample_conv(trash->area, trash->data);
6591 if (sc != NULL) {
6592 ha_warning("Trying to register converter 'lua.%s' more than once. "
6593 "This will become a hard error in version 2.5.\n", name);
6594 }
6595
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006596 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006597 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006598 if (!sck)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006599 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006600 fcn = calloc(1, sizeof(*fcn));
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006601 if (!fcn)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006602 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006603
6604 /* Fill fcn. */
6605 fcn->name = strdup(name);
6606 if (!fcn->name)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006607 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006608 fcn->function_ref = ref;
6609
6610 /* List head */
6611 sck->list.n = sck->list.p = NULL;
6612
6613 /* converter keyword. */
6614 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006615 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006616 if (!sck->kw[0].kw)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006617 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006618
6619 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
6620 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01006621 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 +01006622 sck->kw[0].val_args = NULL;
6623 sck->kw[0].in_type = SMP_T_STR;
6624 sck->kw[0].out_type = SMP_T_STR;
6625 sck->kw[0].private = fcn;
6626
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006627 /* Register this new converter */
6628 sample_register_convs(sck);
6629
6630 return 0;
6631}
6632
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006633/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006634 * "sample-fetch" functions. It expects a converter name used
6635 * in the haproxy configuration file, and an LUA function.
6636 */
6637__LJMP static int hlua_register_fetches(lua_State *L)
6638{
6639 const char *name;
6640 int ref;
6641 int len;
6642 struct sample_fetch_kw_list *sfk;
6643 struct hlua_function *fcn;
Thierry Fournier04cbfd72020-11-28 20:41:07 +01006644 struct sample_fetch *sf;
6645 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006646
6647 MAY_LJMP(check_args(L, 2, "register_fetches"));
6648
6649 /* First argument : sample-fetch name. */
6650 name = MAY_LJMP(luaL_checkstring(L, 1));
6651
6652 /* Second argument : lua function. */
6653 ref = MAY_LJMP(hlua_checkfunction(L, 2));
6654
Thierry Fournier04cbfd72020-11-28 20:41:07 +01006655 /* Check if the sample-fetch is already registered */
6656 trash = get_trash_chunk();
6657 chunk_printf(trash, "lua.%s", name);
6658 sf = find_sample_fetch(trash->area, trash->data);
6659 if (sf != NULL) {
6660 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
6661 "This will become a hard error in version 2.5.\n", name);
6662 }
6663
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006664 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006665 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006666 if (!sfk)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006667 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006668 fcn = calloc(1, sizeof(*fcn));
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006669 if (!fcn)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006670 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006671
6672 /* Fill fcn. */
6673 fcn->name = strdup(name);
6674 if (!fcn->name)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006675 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006676 fcn->function_ref = ref;
6677
6678 /* List head */
6679 sfk->list.n = sfk->list.p = NULL;
6680
6681 /* sample-fetch keyword. */
6682 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006683 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006684 if (!sfk->kw[0].kw)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006685 return luaL_error(L, "Lua out of memory error.");
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006686
6687 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
6688 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01006689 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 +01006690 sfk->kw[0].val_args = NULL;
6691 sfk->kw[0].out_type = SMP_T_STR;
6692 sfk->kw[0].use = SMP_USE_HTTP_ANY;
6693 sfk->kw[0].val = 0;
6694 sfk->kw[0].private = fcn;
6695
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006696 /* Register this new fetch. */
6697 sample_register_fetches(sfk);
6698
6699 return 0;
6700}
6701
Christopher Faulet501465d2020-02-26 14:54:16 +01006702/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006703 */
Christopher Faulet501465d2020-02-26 14:54:16 +01006704__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006705{
6706 struct hlua *hlua = hlua_gethlua(L);
6707 unsigned int delay;
6708 unsigned int wakeup_ms;
6709
6710 MAY_LJMP(check_args(L, 1, "wake_time"));
6711
6712 delay = MAY_LJMP(luaL_checkinteger(L, 1));
6713 wakeup_ms = tick_add(now_ms, delay);
6714 hlua->wake_time = wakeup_ms;
6715 return 0;
6716}
6717
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006718/* This function is a wrapper to execute each LUA function declared as an action
6719 * wrapper during the initialisation period. This function may return any
6720 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
6721 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
6722 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006723 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006724static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02006725 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006726{
6727 char **arg;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006728 unsigned int hflags = 0;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006729 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006730 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006731
6732 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006733 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
6734 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
6735 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
6736 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006737 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006738 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006739 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006740 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006741
Willy Tarreau87b09662015-04-03 00:22:06 +02006742 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006743 * Lua context can be not initialized. This behavior
6744 * permits to save performances because a systematic
6745 * Lua initialization cause 5% performances loss.
6746 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006747 if (!s->hlua) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01006748 s->hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006749 if (!s->hlua) {
6750 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
6751 rule->arg.hlua_rule->fcn.name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006752 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006753 }
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01006754 if (!hlua_ctx_init(s->hlua, s->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006755 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
6756 rule->arg.hlua_rule->fcn.name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006757 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006758 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006759 }
6760
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006761 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006762 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006763
6764 /* The following Lua calls can fail. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006765 if (!SET_SAFE_LJMP(s->hlua->T)) {
6766 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
6767 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006768 else
6769 error = "critical error";
6770 SEND_ERR(px, "Lua function '%s': %s.\n",
6771 rule->arg.hlua_rule->fcn.name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006772 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006773 }
6774
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006775 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006776 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006777 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006778 rule->arg.hlua_rule->fcn.name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006779 RESET_SAFE_LJMP(s->hlua->T);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006780 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006781 }
6782
6783 /* Restore the function in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006784 lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, rule->arg.hlua_rule->fcn.function_ref);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006785
Willy Tarreau87b09662015-04-03 00:22:06 +02006786 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006787 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006788 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006789 rule->arg.hlua_rule->fcn.name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006790 RESET_SAFE_LJMP(s->hlua->T);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006791 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006792 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006793 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006794
6795 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006796 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006797 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006798 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006799 rule->arg.hlua_rule->fcn.name);
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006800 RESET_SAFE_LJMP(s->hlua->T);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006801 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006802 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006803 lua_pushstring(s->hlua->T, *arg);
6804 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006805 }
6806
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006807 /* Now the execution is safe. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006808 RESET_SAFE_LJMP(s->hlua->T);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006809
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006810 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006811 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006812 }
6813
6814 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01006815 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006816 /* finished. */
6817 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006818 /* Catch the return value */
6819 if (lua_gettop(s->hlua->T) > 0)
6820 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006821
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006822 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02006823 if (act_ret == ACT_RET_YIELD) {
6824 if (flags & ACT_OPT_FINAL)
6825 goto err_yield;
6826
Christopher Faulet8f587ea2020-07-28 12:01:55 +02006827 if (dir == SMP_OPT_DIR_REQ)
6828 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
6829 s->hlua->wake_time);
6830 else
6831 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
6832 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006833 }
6834 goto end;
6835
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006836 /* yield. */
6837 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01006838 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02006839 if (dir == SMP_OPT_DIR_REQ)
6840 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
6841 s->hlua->wake_time);
6842 else
6843 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
6844 s->hlua->wake_time);
6845
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006846 /* Some actions can be wake up when a "write" event
6847 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006848 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006849 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02006850 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006851 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006852 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006853 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006854 act_ret = ACT_RET_YIELD;
6855 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006856
6857 /* finished with error. */
6858 case HLUA_E_ERRMSG:
6859 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006860 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006861 rule->arg.hlua_rule->fcn.name, lua_tostring(s->hlua->T, -1));
6862 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006863 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006864
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006865 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006866 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn.name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006867 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006868
6869 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006870 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn.name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006871 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006872
6873 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02006874 err_yield:
6875 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006876 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
6877 rule->arg.hlua_rule->fcn.name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006878 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006879
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006880 case HLUA_E_ERR:
6881 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006882 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006883 rule->arg.hlua_rule->fcn.name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006884
6885 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006886 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006887 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006888
6889 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02006890 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02006891 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006892 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006893}
6894
Olivier Houchard9f6af332018-05-25 14:04:04 +02006895struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned short state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006896{
Olivier Houchard9f6af332018-05-25 14:04:04 +02006897 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006898
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006899 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02006900 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02006901 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006902}
6903
6904static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
6905{
6906 struct stream_interface *si = ctx->owner;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01006907 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006908 struct task *task;
6909 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006910 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006911
Willy Tarreaubafbe012017-11-24 17:34:44 +01006912 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01006913 if (!hlua) {
6914 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
6915 ctx->rule->arg.hlua_rule->fcn.name);
6916 return 0;
6917 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006918 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01006919 ctx->ctx.hlua_apptcp.hlua = hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006920 ctx->ctx.hlua_apptcp.flags = 0;
6921
6922 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01006923 task = task_new(tid_bit);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006924 if (!task) {
6925 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
6926 ctx->rule->arg.hlua_rule->fcn.name);
6927 return 0;
6928 }
6929 task->nice = 0;
6930 task->context = ctx;
6931 task->process = hlua_applet_wakeup;
6932 ctx->ctx.hlua_apptcp.task = task;
6933
6934 /* In the execution wrappers linked with a stream, the
6935 * Lua context can be not initialized. This behavior
6936 * permits to save performances because a systematic
6937 * Lua initialization cause 5% performances loss.
6938 */
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01006939 if (!hlua_ctx_init(hlua, task, 0)) {
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006940 SEND_ERR(px, "Lua applet tcp '%s': can't initialize Lua context.\n",
6941 ctx->rule->arg.hlua_rule->fcn.name);
6942 return 0;
6943 }
6944
6945 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02006946 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006947
6948 /* The following Lua calls can fail. */
6949 if (!SET_SAFE_LJMP(hlua->T)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01006950 if (lua_type(hlua->T, -1) == LUA_TSTRING)
6951 error = lua_tostring(hlua->T, -1);
6952 else
6953 error = "critical error";
6954 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
6955 ctx->rule->arg.hlua_rule->fcn.name, error);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006956 return 0;
6957 }
6958
6959 /* Check stack available size. */
6960 if (!lua_checkstack(hlua->T, 1)) {
6961 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
6962 ctx->rule->arg.hlua_rule->fcn.name);
6963 RESET_SAFE_LJMP(hlua->T);
6964 return 0;
6965 }
6966
6967 /* Restore the function in the stack. */
6968 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn.function_ref);
6969
6970 /* Create and and push object stream in the stack. */
6971 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
6972 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
6973 ctx->rule->arg.hlua_rule->fcn.name);
6974 RESET_SAFE_LJMP(hlua->T);
6975 return 0;
6976 }
6977 hlua->nargs = 1;
6978
6979 /* push keywords in the stack. */
6980 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
6981 if (!lua_checkstack(hlua->T, 1)) {
6982 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
6983 ctx->rule->arg.hlua_rule->fcn.name);
6984 RESET_SAFE_LJMP(hlua->T);
6985 return 0;
6986 }
6987 lua_pushstring(hlua->T, *arg);
6988 hlua->nargs++;
6989 }
6990
6991 RESET_SAFE_LJMP(hlua->T);
6992
6993 /* Wakeup the applet ASAP. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01006994 si_cant_get(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01006995 si_rx_endp_more(si);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02006996
6997 return 1;
6998}
6999
Willy Tarreau60409db2019-08-21 14:14:50 +02007000void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007001{
7002 struct stream_interface *si = ctx->owner;
7003 struct stream *strm = si_strm(si);
7004 struct channel *res = si_ic(si);
7005 struct act_rule *rule = ctx->rule;
7006 struct proxy *px = strm->be;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007007 struct hlua *hlua = ctx->ctx.hlua_apptcp.hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007008
7009 /* The applet execution is already done. */
Olivier Houchard594c8c52018-08-28 14:41:31 +02007010 if (ctx->ctx.hlua_apptcp.flags & APPLET_DONE) {
7011 /* eat the whole request */
7012 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007013 return;
Olivier Houchard594c8c52018-08-28 14:41:31 +02007014 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007015
7016 /* If the stream is disconnect or closed, ldo nothing. */
7017 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7018 return;
7019
7020 /* Execute the function. */
7021 switch (hlua_ctx_resume(hlua, 1)) {
7022 /* finished. */
7023 case HLUA_E_OK:
7024 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7025
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007026 /* eat the whole request */
Willy Tarreaua79021a2018-06-15 18:07:57 +02007027 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007028 res->flags |= CF_READ_NULL;
7029 si_shutr(si);
7030 return;
7031
7032 /* yield. */
7033 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01007034 if (hlua->wake_time != TICK_ETERNITY)
7035 task_schedule(ctx->ctx.hlua_apptcp.task, hlua->wake_time);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007036 return;
7037
7038 /* finished with error. */
7039 case HLUA_E_ERRMSG:
7040 /* Display log. */
7041 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
7042 rule->arg.hlua_rule->fcn.name, lua_tostring(hlua->T, -1));
7043 lua_pop(hlua->T, 1);
7044 goto error;
7045
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007046 case HLUA_E_ETMOUT:
7047 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
7048 rule->arg.hlua_rule->fcn.name);
7049 goto error;
7050
7051 case HLUA_E_NOMEM:
7052 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
7053 rule->arg.hlua_rule->fcn.name);
7054 goto error;
7055
7056 case HLUA_E_YIELD: /* unexpected */
7057 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
7058 rule->arg.hlua_rule->fcn.name);
7059 goto error;
7060
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007061 case HLUA_E_ERR:
7062 /* Display log. */
7063 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
7064 rule->arg.hlua_rule->fcn.name);
7065 goto error;
7066
7067 default:
7068 goto error;
7069 }
7070
7071error:
7072
7073 /* For all other cases, just close the stream. */
7074 si_shutw(si);
7075 si_shutr(si);
7076 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7077}
7078
7079static void hlua_applet_tcp_release(struct appctx *ctx)
7080{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007081 task_destroy(ctx->ctx.hlua_apptcp.task);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007082 ctx->ctx.hlua_apptcp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007083 hlua_ctx_destroy(ctx->ctx.hlua_apptcp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007084 ctx->ctx.hlua_apptcp.hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007085}
7086
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007087/* The function returns 1 if the initialisation is complete, 0 if
7088 * an errors occurs and -1 if more data are required for initializing
7089 * the applet.
7090 */
7091static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7092{
7093 struct stream_interface *si = ctx->owner;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007094 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007095 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007096 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007097 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007098 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007099
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007100 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01007101 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007102 if (!hlua) {
7103 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
7104 ctx->rule->arg.hlua_rule->fcn.name);
7105 return 0;
7106 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007107 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007108 ctx->ctx.hlua_apphttp.hlua = hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007109 ctx->ctx.hlua_apphttp.left_bytes = -1;
7110 ctx->ctx.hlua_apphttp.flags = 0;
7111
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01007112 if (txn->req.flags & HTTP_MSGF_VER_11)
7113 ctx->ctx.hlua_apphttp.flags |= APPLET_HTTP11;
7114
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007115 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007116 task = task_new(tid_bit);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007117 if (!task) {
7118 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
7119 ctx->rule->arg.hlua_rule->fcn.name);
7120 return 0;
7121 }
7122 task->nice = 0;
7123 task->context = ctx;
7124 task->process = hlua_applet_wakeup;
7125 ctx->ctx.hlua_apphttp.task = task;
7126
7127 /* In the execution wrappers linked with a stream, the
7128 * Lua context can be not initialized. This behavior
7129 * permits to save performances because a systematic
7130 * Lua initialization cause 5% performances loss.
7131 */
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01007132 if (!hlua_ctx_init(hlua, task, 0)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007133 SEND_ERR(px, "Lua applet http '%s': can't initialize Lua context.\n",
7134 ctx->rule->arg.hlua_rule->fcn.name);
7135 return 0;
7136 }
7137
7138 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007139 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007140
7141 /* The following Lua calls can fail. */
7142 if (!SET_SAFE_LJMP(hlua->T)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007143 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7144 error = lua_tostring(hlua->T, -1);
7145 else
7146 error = "critical error";
7147 SEND_ERR(px, "Lua applet http '%s': %s.\n",
7148 ctx->rule->arg.hlua_rule->fcn.name, error);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007149 return 0;
7150 }
7151
7152 /* Check stack available size. */
7153 if (!lua_checkstack(hlua->T, 1)) {
7154 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
7155 ctx->rule->arg.hlua_rule->fcn.name);
7156 RESET_SAFE_LJMP(hlua->T);
7157 return 0;
7158 }
7159
7160 /* Restore the function in the stack. */
7161 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn.function_ref);
7162
7163 /* Create and and push object stream in the stack. */
7164 if (!hlua_applet_http_new(hlua->T, ctx)) {
7165 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
7166 ctx->rule->arg.hlua_rule->fcn.name);
7167 RESET_SAFE_LJMP(hlua->T);
7168 return 0;
7169 }
7170 hlua->nargs = 1;
7171
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007172 /* push keywords in the stack. */
7173 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7174 if (!lua_checkstack(hlua->T, 1)) {
7175 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
7176 ctx->rule->arg.hlua_rule->fcn.name);
7177 RESET_SAFE_LJMP(hlua->T);
7178 return 0;
7179 }
7180 lua_pushstring(hlua->T, *arg);
7181 hlua->nargs++;
7182 }
7183
7184 RESET_SAFE_LJMP(hlua->T);
7185
7186 /* Wakeup the applet when data is ready for read. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007187 si_cant_get(si);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007188
7189 return 1;
7190}
7191
Willy Tarreau60409db2019-08-21 14:14:50 +02007192void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007193{
7194 struct stream_interface *si = ctx->owner;
7195 struct stream *strm = si_strm(si);
7196 struct channel *req = si_oc(si);
7197 struct channel *res = si_ic(si);
7198 struct act_rule *rule = ctx->rule;
7199 struct proxy *px = strm->be;
7200 struct hlua *hlua = ctx->ctx.hlua_apphttp.hlua;
7201 struct htx *req_htx, *res_htx;
7202
7203 res_htx = htx_from_buf(&res->buf);
7204
7205 /* If the stream is disconnect or closed, ldo nothing. */
7206 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7207 goto out;
7208
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007209 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007210 if (!b_size(&res->buf)) {
7211 si_rx_room_blk(si);
7212 goto out;
7213 }
7214 /* check that the output is not closed */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007215 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007216 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7217
7218 /* Set the currently running flag. */
7219 if (!HLUA_IS_RUNNING(hlua) &&
7220 !(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
7221 struct htx_blk *blk;
7222 size_t count = co_data(req);
7223
7224 if (!count) {
7225 si_cant_get(si);
7226 goto out;
7227 }
7228
7229 /* We need to flush the request header. This left the body for
7230 * the Lua.
7231 */
7232 req_htx = htx_from_buf(&req->buf);
Christopher Fauleta3f15502019-05-13 15:27:23 +02007233 blk = htx_get_first_blk(req_htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007234 while (count && blk) {
7235 enum htx_blk_type type = htx_get_blk_type(blk);
7236 uint32_t sz = htx_get_blksz(blk);
7237
7238 if (sz > count) {
7239 si_cant_get(si);
Christopher Faulet0ae79d02019-02-27 21:36:59 +01007240 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007241 goto out;
7242 }
7243
7244 count -= sz;
7245 co_set_data(req, co_data(req) - sz);
7246 blk = htx_remove_blk(req_htx, blk);
7247
7248 if (type == HTX_BLK_EOH)
7249 break;
7250 }
Christopher Faulet0ae79d02019-02-27 21:36:59 +01007251 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007252 }
7253
7254 /* Executes The applet if it is not done. */
7255 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
7256
7257 /* Execute the function. */
7258 switch (hlua_ctx_resume(hlua, 1)) {
7259 /* finished. */
7260 case HLUA_E_OK:
7261 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7262 break;
7263
7264 /* yield. */
7265 case HLUA_E_AGAIN:
7266 if (hlua->wake_time != TICK_ETERNITY)
7267 task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007268 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007269
7270 /* finished with error. */
7271 case HLUA_E_ERRMSG:
7272 /* Display log. */
7273 SEND_ERR(px, "Lua applet http '%s': %s.\n",
7274 rule->arg.hlua_rule->fcn.name, lua_tostring(hlua->T, -1));
7275 lua_pop(hlua->T, 1);
7276 goto error;
7277
7278 case HLUA_E_ETMOUT:
7279 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
7280 rule->arg.hlua_rule->fcn.name);
7281 goto error;
7282
7283 case HLUA_E_NOMEM:
7284 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
7285 rule->arg.hlua_rule->fcn.name);
7286 goto error;
7287
7288 case HLUA_E_YIELD: /* unexpected */
7289 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
7290 rule->arg.hlua_rule->fcn.name);
7291 goto error;
7292
7293 case HLUA_E_ERR:
7294 /* Display log. */
7295 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
7296 rule->arg.hlua_rule->fcn.name);
7297 goto error;
7298
7299 default:
7300 goto error;
7301 }
7302 }
7303
7304 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007305 if (ctx->ctx.hlua_apphttp.flags & APPLET_RSP_SENT)
7306 goto done;
7307
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007308 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT))
7309 goto error;
7310
Christopher Faulet54b5e212019-06-04 10:08:28 +02007311 /* Don't add TLR because mux-h1 will take care of it */
Willy Tarreauf1ea47d2020-07-23 06:53:27 +02007312 res_htx->flags |= HTX_FL_EOI; /* no more data are expected. Only EOM remains to add now */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007313 if (!htx_add_endof(res_htx, HTX_BLK_EOM)) {
7314 si_rx_room_blk(si);
7315 goto out;
7316 }
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01007317 channel_add_input(res, 1);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007318 strm->txn->status = ctx->ctx.hlua_apphttp.status;
7319 ctx->ctx.hlua_apphttp.flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007320 }
7321
7322 done:
7323 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007324 if (!(res->flags & CF_SHUTR)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007325 res->flags |= CF_READ_NULL;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007326 si_shutr(si);
7327 }
7328
7329 /* eat the whole request */
7330 if (co_data(req)) {
7331 req_htx = htx_from_buf(&req->buf);
7332 co_htx_skip(req, req_htx, co_data(req));
7333 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007334 }
7335 }
7336
7337 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007338 htx_to_buf(res_htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007339 return;
7340
7341 error:
7342
7343 /* If we are in HTTP mode, and we are not send any
7344 * data, return a 500 server error in best effort:
7345 * if there is no room available in the buffer,
7346 * just close the connection.
7347 */
7348 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02007349 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007350
7351 channel_erase(res);
7352 res->buf.data = b_data(err);
7353 memcpy(res->buf.area, b_head(err), b_data(err));
7354 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01007355 channel_add_input(res, res_htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007356 }
7357 if (!(strm->flags & SF_ERR_MASK))
7358 strm->flags |= SF_ERR_RESOURCE;
7359 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7360 goto done;
7361}
7362
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007363static void hlua_applet_http_release(struct appctx *ctx)
7364{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007365 task_destroy(ctx->ctx.hlua_apphttp.task);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007366 ctx->ctx.hlua_apphttp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007367 hlua_ctx_destroy(ctx->ctx.hlua_apphttp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007368 ctx->ctx.hlua_apphttp.hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007369}
7370
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007371/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007372 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007373 *
7374 * This function can fail with an abort() due to an Lua critical error.
7375 * We are in the configuration parsing process of HAProxy, this abort() is
7376 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007377 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007378static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
7379 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007380{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007381 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007382 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007383
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007384 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007385 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007386 if (!rule->arg.hlua_rule) {
7387 memprintf(err, "out of memory error");
Thierry FOURNIERafa80492015-08-19 09:04:15 +02007388 return ACT_RET_PRS_ERR;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007389 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007390
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007391 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02007392 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
7393 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007394 if (!rule->arg.hlua_rule->args) {
7395 memprintf(err, "out of memory error");
7396 return ACT_RET_PRS_ERR;
7397 }
7398
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007399 /* Reference the Lua function and store the reference. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007400 rule->arg.hlua_rule->fcn = *fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007401
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007402 /* Expect some arguments */
7403 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007404 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007405 memprintf(err, "expect %d arguments", fcn->nargs);
7406 return ACT_RET_PRS_ERR;
7407 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007408 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007409 if (!rule->arg.hlua_rule->args[i]) {
7410 memprintf(err, "out of memory error");
7411 return ACT_RET_PRS_ERR;
7412 }
7413 (*cur_arg)++;
7414 }
7415 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007416
Thierry FOURNIER42148732015-09-02 17:17:33 +02007417 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007418 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02007419 return ACT_RET_PRS_OK;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007420}
7421
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007422static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
7423 struct act_rule *rule, char **err)
7424{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007425 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007426
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007427 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007428 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007429 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007430 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007431 * the call of this analyzer.
7432 */
7433 if (rule->from != ACT_F_HTTP_REQ) {
7434 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
7435 return ACT_RET_PRS_ERR;
7436 }
7437
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007438 /* Memory for the rule. */
7439 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7440 if (!rule->arg.hlua_rule) {
7441 memprintf(err, "out of memory error");
7442 return ACT_RET_PRS_ERR;
7443 }
7444
7445 /* Reference the Lua function and store the reference. */
7446 rule->arg.hlua_rule->fcn = *fcn;
7447
7448 /* TODO: later accept arguments. */
7449 rule->arg.hlua_rule->args = NULL;
7450
7451 /* Add applet pointer in the rule. */
7452 rule->applet.obj_type = OBJ_TYPE_APPLET;
7453 rule->applet.name = fcn->name;
7454 rule->applet.init = hlua_applet_http_init;
7455 rule->applet.fct = hlua_applet_http_fct;
7456 rule->applet.release = hlua_applet_http_release;
7457 rule->applet.timeout = hlua_timeout_applet;
7458
7459 return ACT_RET_PRS_OK;
7460}
7461
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007462/* This function is an LUA binding used for registering
7463 * "sample-conv" functions. It expects a converter name used
7464 * in the haproxy configuration file, and an LUA function.
7465 */
7466__LJMP static int hlua_register_action(lua_State *L)
7467{
7468 struct action_kw_list *akl;
7469 const char *name;
7470 int ref;
7471 int len;
7472 struct hlua_function *fcn;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007473 int nargs;
Thierry Fournier04cbfd72020-11-28 20:41:07 +01007474 struct buffer *trash;
7475 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007476
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007477 /* Initialise the number of expected arguments at 0. */
7478 nargs = 0;
7479
7480 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7481 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007482
7483 /* First argument : converter name. */
7484 name = MAY_LJMP(luaL_checkstring(L, 1));
7485
7486 /* Second argument : environment. */
7487 if (lua_type(L, 2) != LUA_TTABLE)
7488 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7489
7490 /* Third argument : lua function. */
7491 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7492
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007493 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007494 if (lua_gettop(L) >= 4)
7495 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
7496
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007497 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007498 lua_pushnil(L);
7499 while (lua_next(L, 2) != 0) {
7500 if (lua_type(L, -1) != LUA_TSTRING)
7501 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7502
Thierry Fournier04cbfd72020-11-28 20:41:07 +01007503 /* Check if action exists */
7504 trash = get_trash_chunk();
7505 chunk_printf(trash, "lua.%s", name);
7506 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
7507 akw = tcp_req_cont_action(trash->area);
7508 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
7509 akw = tcp_res_cont_action(trash->area);
7510 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
7511 akw = action_http_req_custom(trash->area);
7512 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
7513 akw = action_http_res_custom(trash->area);
7514 } else {
7515 akw = NULL;
7516 }
7517 if (akw != NULL) {
7518 ha_warning("Trying to register action 'lua.%s' more than once. "
7519 "This will become a hard error in version 2.5.\n", name);
7520 }
7521
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007522 /* Check required environment. Only accepted "http" or "tcp". */
7523 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007524 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007525 if (!akl)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007526 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007527 fcn = calloc(1, sizeof(*fcn));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007528 if (!fcn)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007529 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007530
7531 /* Fill fcn. */
7532 fcn->name = strdup(name);
7533 if (!fcn->name)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007534 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007535 fcn->function_ref = ref;
7536
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007537 /* Set the expected number od arguments. */
7538 fcn->nargs = nargs;
7539
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007540 /* List head */
7541 akl->list.n = akl->list.p = NULL;
7542
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007543 /* action keyword. */
7544 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007545 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007546 if (!akl->kw[0].kw)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007547 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007548
7549 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
7550
7551 akl->kw[0].match_pfx = 0;
7552 akl->kw[0].private = fcn;
7553 akl->kw[0].parse = action_register_lua;
7554
7555 /* select the action registering point. */
7556 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
7557 tcp_req_cont_keywords_register(akl);
7558 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
7559 tcp_res_cont_keywords_register(akl);
7560 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
7561 http_req_keywords_register(akl);
7562 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
7563 http_res_keywords_register(akl);
7564 else
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007565 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007566 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
7567 "are expected.", lua_tostring(L, -1)));
7568
7569 /* pop the environment string. */
7570 lua_pop(L, 1);
7571 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007572 return ACT_RET_PRS_OK;
7573}
7574
7575static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
7576 struct act_rule *rule, char **err)
7577{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007578 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007579
Christopher Faulet280f85b2019-07-15 15:02:04 +02007580 if (px->mode == PR_MODE_HTTP) {
7581 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +01007582 return ACT_RET_PRS_ERR;
7583 }
7584
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007585 /* Memory for the rule. */
7586 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7587 if (!rule->arg.hlua_rule) {
7588 memprintf(err, "out of memory error");
7589 return ACT_RET_PRS_ERR;
7590 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007591
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007592 /* Reference the Lua function and store the reference. */
7593 rule->arg.hlua_rule->fcn = *fcn;
7594
7595 /* TODO: later accept arguments. */
7596 rule->arg.hlua_rule->args = NULL;
7597
7598 /* Add applet pointer in the rule. */
7599 rule->applet.obj_type = OBJ_TYPE_APPLET;
7600 rule->applet.name = fcn->name;
7601 rule->applet.init = hlua_applet_tcp_init;
7602 rule->applet.fct = hlua_applet_tcp_fct;
7603 rule->applet.release = hlua_applet_tcp_release;
7604 rule->applet.timeout = hlua_timeout_applet;
7605
7606 return 0;
7607}
7608
7609/* This function is an LUA binding used for registering
7610 * "sample-conv" functions. It expects a converter name used
7611 * in the haproxy configuration file, and an LUA function.
7612 */
7613__LJMP static int hlua_register_service(lua_State *L)
7614{
7615 struct action_kw_list *akl;
7616 const char *name;
7617 const char *env;
7618 int ref;
7619 int len;
7620 struct hlua_function *fcn;
Thierry Fournier04cbfd72020-11-28 20:41:07 +01007621 struct buffer *trash;
7622 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007623
7624 MAY_LJMP(check_args(L, 3, "register_service"));
7625
7626 /* First argument : converter name. */
7627 name = MAY_LJMP(luaL_checkstring(L, 1));
7628
7629 /* Second argument : environment. */
7630 env = MAY_LJMP(luaL_checkstring(L, 2));
7631
7632 /* Third argument : lua function. */
7633 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7634
Thierry Fournier04cbfd72020-11-28 20:41:07 +01007635 /* Check for service already registered */
7636 trash = get_trash_chunk();
7637 chunk_printf(trash, "lua.%s", name);
7638 akw = service_find(trash->area);
7639 if (akw != NULL) {
7640 ha_warning("Trying to register service 'lua.%s' more than once. "
7641 "This will become a hard error in version 2.5.\n", name);
7642 }
7643
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007644 /* Allocate and fill the sample fetch keyword struct. */
7645 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
7646 if (!akl)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007647 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007648 fcn = calloc(1, sizeof(*fcn));
7649 if (!fcn)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007650 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007651
7652 /* Fill fcn. */
7653 len = strlen("<lua.>") + strlen(name) + 1;
7654 fcn->name = calloc(1, len);
7655 if (!fcn->name)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007656 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007657 snprintf((char *)fcn->name, len, "<lua.%s>", name);
7658 fcn->function_ref = ref;
7659
7660 /* List head */
7661 akl->list.n = akl->list.p = NULL;
7662
7663 /* converter keyword. */
7664 len = strlen("lua.") + strlen(name) + 1;
7665 akl->kw[0].kw = calloc(1, len);
7666 if (!akl->kw[0].kw)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007667 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007668
7669 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
7670
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +01007671 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007672 if (strcmp(env, "tcp") == 0)
7673 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007674 else if (strcmp(env, "http") == 0)
7675 akl->kw[0].parse = action_register_service_http;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007676 else
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007677 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +01007678 "'tcp' or 'http' are expected.", env));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007679
7680 akl->kw[0].match_pfx = 0;
7681 akl->kw[0].private = fcn;
7682
7683 /* End of array. */
7684 memset(&akl->kw[1], 0, sizeof(*akl->kw));
7685
7686 /* Register this new converter */
7687 service_keywords_register(akl);
7688
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007689 return 0;
7690}
7691
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007692/* This function initialises Lua cli handler. It copies the
7693 * arguments in the Lua stack and create channel IO objects.
7694 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02007695static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007696{
7697 struct hlua *hlua;
7698 struct hlua_function *fcn;
7699 int i;
7700 const char *error;
7701
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007702 fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007703 appctx->ctx.hlua_cli.fcn = private;
7704
Willy Tarreaubafbe012017-11-24 17:34:44 +01007705 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007706 if (!hlua) {
7707 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007708 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007709 }
7710 HLUA_INIT(hlua);
7711 appctx->ctx.hlua_cli.hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007712
7713 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +05007714 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007715 * applet_http. It is absolutely compatible.
7716 */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007717 appctx->ctx.hlua_cli.task = task_new(tid_bit);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007718 if (!appctx->ctx.hlua_cli.task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +01007719 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007720 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007721 }
7722 appctx->ctx.hlua_cli.task->nice = 0;
7723 appctx->ctx.hlua_cli.task->context = appctx;
7724 appctx->ctx.hlua_cli.task->process = hlua_applet_wakeup;
7725
7726 /* Initialises the Lua context */
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01007727 if (!hlua_ctx_init(hlua, appctx->ctx.hlua_cli.task, 0)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007728 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007729 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007730 }
7731
7732 /* The following Lua calls can fail. */
7733 if (!SET_SAFE_LJMP(hlua->T)) {
7734 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7735 error = lua_tostring(hlua->T, -1);
7736 else
7737 error = "critical error";
7738 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
7739 goto error;
7740 }
7741
7742 /* Check stack available size. */
7743 if (!lua_checkstack(hlua->T, 2)) {
7744 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7745 goto error;
7746 }
7747
7748 /* Restore the function in the stack. */
7749 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref);
7750
7751 /* Once the arguments parsed, the CLI is like an AppletTCP,
7752 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007753 */
7754 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
7755 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7756 goto error;
7757 }
7758 hlua->nargs = 1;
7759
7760 /* push keywords in the stack. */
7761 for (i = 0; *args[i]; i++) {
7762 /* Check stack available size. */
7763 if (!lua_checkstack(hlua->T, 1)) {
7764 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7765 goto error;
7766 }
7767 lua_pushstring(hlua->T, args[i]);
7768 hlua->nargs++;
7769 }
7770
7771 /* We must initialize the execution timeouts. */
7772 hlua->max_time = hlua_timeout_session;
7773
7774 /* At this point the execution is safe. */
7775 RESET_SAFE_LJMP(hlua->T);
7776
7777 /* It's ok */
7778 return 0;
7779
7780 /* It's not ok. */
7781error:
7782 RESET_SAFE_LJMP(hlua->T);
7783 hlua_ctx_destroy(hlua);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007784 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007785 return 1;
7786}
7787
7788static int hlua_cli_io_handler_fct(struct appctx *appctx)
7789{
7790 struct hlua *hlua;
7791 struct stream_interface *si;
7792 struct hlua_function *fcn;
7793
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007794 hlua = appctx->ctx.hlua_cli.hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007795 si = appctx->owner;
Willy Tarreau8ae4f752016-12-14 15:41:45 +01007796 fcn = appctx->ctx.hlua_cli.fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007797
7798 /* If the stream is disconnect or closed, ldo nothing. */
7799 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7800 return 1;
7801
7802 /* Execute the function. */
7803 switch (hlua_ctx_resume(hlua, 1)) {
7804
7805 /* finished. */
7806 case HLUA_E_OK:
7807 return 1;
7808
7809 /* yield. */
7810 case HLUA_E_AGAIN:
7811 /* We want write. */
7812 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreaudb398432018-11-15 11:08:52 +01007813 si_rx_room_blk(si);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007814 /* Set the timeout. */
7815 if (hlua->wake_time != TICK_ETERNITY)
7816 task_schedule(hlua->task, hlua->wake_time);
7817 return 0;
7818
7819 /* finished with error. */
7820 case HLUA_E_ERRMSG:
7821 /* Display log. */
7822 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
7823 fcn->name, lua_tostring(hlua->T, -1));
7824 lua_pop(hlua->T, 1);
7825 return 1;
7826
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007827 case HLUA_E_ETMOUT:
7828 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
7829 fcn->name);
7830 return 1;
7831
7832 case HLUA_E_NOMEM:
7833 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
7834 fcn->name);
7835 return 1;
7836
7837 case HLUA_E_YIELD: /* unexpected */
7838 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
7839 fcn->name);
7840 return 1;
7841
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007842 case HLUA_E_ERR:
7843 /* Display log. */
7844 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
7845 fcn->name);
7846 return 1;
7847
7848 default:
7849 return 1;
7850 }
7851
7852 return 1;
7853}
7854
7855static void hlua_cli_io_release_fct(struct appctx *appctx)
7856{
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007857 hlua_ctx_destroy(appctx->ctx.hlua_cli.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007858 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007859}
7860
7861/* This function is an LUA binding used for registering
7862 * new keywords in the cli. It expects a list of keywords
7863 * which are the "path". It is limited to 5 keywords. A
7864 * description of the command, a function to be executed
7865 * for the parsing and a function for io handlers.
7866 */
7867__LJMP static int hlua_register_cli(lua_State *L)
7868{
7869 struct cli_kw_list *cli_kws;
7870 const char *message;
7871 int ref_io;
7872 int len;
7873 struct hlua_function *fcn;
7874 int index;
7875 int i;
Thierry Fournier04cbfd72020-11-28 20:41:07 +01007876 struct buffer *trash;
7877 const char *kw[5];
7878 struct cli_kw *cli_kw;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007879
7880 MAY_LJMP(check_args(L, 3, "register_cli"));
7881
7882 /* First argument : an array of maximum 5 keywords. */
7883 if (!lua_istable(L, 1))
7884 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
7885
7886 /* Second argument : string with contextual message. */
7887 message = MAY_LJMP(luaL_checkstring(L, 2));
7888
7889 /* Third and fourth argument : lua function. */
7890 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
7891
Thierry Fournier04cbfd72020-11-28 20:41:07 +01007892 /* Check for CLI service already registered */
7893 trash = get_trash_chunk();
7894 index = 0;
7895 lua_pushnil(L);
7896 memset(kw, 0, sizeof(kw));
7897 while (lua_next(L, 1) != 0) {
7898 if (index >= CLI_PREFIX_KW_NB)
7899 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
7900 if (lua_type(L, -1) != LUA_TSTRING)
7901 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
7902 kw[index] = lua_tostring(L, -1);
7903 if (index == 0)
7904 chunk_printf(trash, "%s", kw[index]);
7905 else
7906 chunk_appendf(trash, " %s", kw[index]);
7907 index++;
7908 lua_pop(L, 1);
7909 }
7910 cli_kw = cli_find_kw_exact((char **)kw);
7911 if (cli_kw != NULL) {
7912 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
7913 "This will become a hard error in version 2.5.\n", trash->area);
7914 }
7915
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007916 /* Allocate and fill the sample fetch keyword struct. */
7917 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
7918 if (!cli_kws)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007919 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007920 fcn = calloc(1, sizeof(*fcn));
7921 if (!fcn)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007922 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007923
7924 /* Fill path. */
7925 index = 0;
7926 lua_pushnil(L);
7927 while(lua_next(L, 1) != 0) {
7928 if (index >= 5)
7929 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
7930 if (lua_type(L, -1) != LUA_TSTRING)
7931 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
7932 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
7933 if (!cli_kws->kw[0].str_kw[index])
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007934 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007935 index++;
7936 lua_pop(L, 1);
7937 }
7938
7939 /* Copy help message. */
7940 cli_kws->kw[0].usage = strdup(message);
7941 if (!cli_kws->kw[0].usage)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007942 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007943
7944 /* Fill fcn io handler. */
7945 len = strlen("<lua.cli>") + 1;
7946 for (i = 0; i < index; i++)
7947 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
7948 fcn->name = calloc(1, len);
7949 if (!fcn->name)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007950 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007951 strncat((char *)fcn->name, "<lua.cli", len);
7952 for (i = 0; i < index; i++) {
7953 strncat((char *)fcn->name, ".", len);
7954 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
7955 }
7956 strncat((char *)fcn->name, ">", len);
7957 fcn->function_ref = ref_io;
7958
7959 /* Fill last entries. */
7960 cli_kws->kw[0].private = fcn;
7961 cli_kws->kw[0].parse = hlua_cli_parse_fct;
7962 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
7963 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
7964
7965 /* Register this new converter */
7966 cli_register_kw(cli_kws);
7967
7968 return 0;
7969}
7970
Thierry FOURNIERbd413492015-03-03 16:52:26 +01007971static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
7972 struct proxy *defpx, const char *file, int line,
7973 char **err, unsigned int *timeout)
7974{
7975 const char *error;
7976
7977 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02007978 if (error == PARSE_TIME_OVER) {
7979 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
7980 args[1], args[0]);
7981 return -1;
7982 }
7983 else if (error == PARSE_TIME_UNDER) {
7984 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
7985 args[1], args[0]);
7986 return -1;
7987 }
7988 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +01007989 memprintf(err, "%s: invalid timeout", args[0]);
7990 return -1;
7991 }
7992 return 0;
7993}
7994
7995static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
7996 struct proxy *defpx, const char *file, int line,
7997 char **err)
7998{
7999 return hlua_read_timeout(args, section_type, curpx, defpx,
8000 file, line, err, &hlua_timeout_session);
8001}
8002
8003static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
8004 struct proxy *defpx, const char *file, int line,
8005 char **err)
8006{
8007 return hlua_read_timeout(args, section_type, curpx, defpx,
8008 file, line, err, &hlua_timeout_task);
8009}
8010
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008011static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
8012 struct proxy *defpx, const char *file, int line,
8013 char **err)
8014{
8015 return hlua_read_timeout(args, section_type, curpx, defpx,
8016 file, line, err, &hlua_timeout_applet);
8017}
8018
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008019static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
8020 struct proxy *defpx, const char *file, int line,
8021 char **err)
8022{
8023 char *error;
8024
8025 hlua_nb_instruction = strtoll(args[1], &error, 10);
8026 if (*error != '\0') {
8027 memprintf(err, "%s: invalid number", args[0]);
8028 return -1;
8029 }
8030 return 0;
8031}
8032
Willy Tarreau32f61e22015-03-18 17:54:59 +01008033static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
8034 struct proxy *defpx, const char *file, int line,
8035 char **err)
8036{
8037 char *error;
8038
8039 if (*(args[1]) == 0) {
8040 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).\n", args[0]);
8041 return -1;
8042 }
8043 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
8044 if (*error != '\0') {
8045 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
8046 return -1;
8047 }
8048 return 0;
8049}
8050
8051
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008052/* This function is called by the main configuration key "lua-load". It loads and
8053 * execute an lua file during the parsing of the HAProxy configuration file. It is
8054 * the main lua entry point.
8055 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008056 * This function runs with the HAProxy keywords API. It returns -1 if an error
8057 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008058 *
8059 * In some error case, LUA set an error message in top of the stack. This function
8060 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008061 *
8062 * This function can fail with an abort() due to an Lua critical error.
8063 * We are in the configuration parsing process of HAProxy, this abort() is
8064 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008065 */
8066static int hlua_load(char **args, int section_type, struct proxy *curpx,
8067 struct proxy *defpx, const char *file, int line,
8068 char **err)
8069{
8070 int error;
8071
Thierry Fournierad6e9c52020-11-29 01:06:24 +01008072 if (*(args[1]) == 0) {
8073 memprintf(err, "'%s' expects a file name as parameter.\n", args[0]);
8074 return -1;
8075 }
8076
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008077 /* Just load and compile the file. */
8078 error = luaL_loadfile(gL.T, args[1]);
8079 if (error) {
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008080 memprintf(err, "error in Lua file '%s': %s", args[1], lua_tostring(gL.T, -1));
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008081 lua_pop(gL.T, 1);
8082 return -1;
8083 }
8084
8085 /* If no syntax error where detected, execute the code. */
8086 error = lua_pcall(gL.T, 0, LUA_MULTRET, 0);
8087 switch (error) {
8088 case LUA_OK:
8089 break;
8090 case LUA_ERRRUN:
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008091 memprintf(err, "Lua runtime error: %s\n", lua_tostring(gL.T, -1));
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008092 lua_pop(gL.T, 1);
8093 return -1;
8094 case LUA_ERRMEM:
Thierry Fournier518017f2020-11-29 00:55:53 +01008095 memprintf(err, "Lua out of memory error\n");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008096 return -1;
8097 case LUA_ERRERR:
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008098 memprintf(err, "Lua message handler error: %s\n", lua_tostring(gL.T, -1));
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008099 lua_pop(gL.T, 1);
8100 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02008101#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008102 case LUA_ERRGCMM:
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008103 memprintf(err, "Lua garbage collector error: %s\n", lua_tostring(gL.T, -1));
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008104 lua_pop(gL.T, 1);
8105 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02008106#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008107 default:
Ilya Shipitsind4259502020-04-08 01:07:56 +05008108 memprintf(err, "Lua unknown error: %s\n", lua_tostring(gL.T, -1));
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008109 lua_pop(gL.T, 1);
8110 return -1;
8111 }
8112
8113 return 0;
8114}
8115
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008116/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
8117 * in the given <ctx>.
8118 */
8119static int hlua_prepend_path(struct hlua ctx, char *type, char *path)
8120{
8121 lua_getglobal(ctx.T, "package"); /* push package variable */
8122 lua_pushstring(ctx.T, path); /* push given path */
8123 lua_pushstring(ctx.T, ";"); /* push semicolon */
8124 lua_getfield(ctx.T, -3, type); /* push old path */
8125 lua_concat(ctx.T, 3); /* concatenate to new path */
8126 lua_setfield(ctx.T, -2, type); /* store new path */
8127 lua_pop(ctx.T, 1); /* pop package variable */
8128
8129 return 0;
8130}
8131
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008132static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
8133 struct proxy *defpx, const char *file, int line,
8134 char **err)
8135{
8136 char *path;
8137 char *type = "path";
8138 if (too_many_args(2, args, err, NULL)) {
8139 return -1;
8140 }
8141
8142 if (!(*args[1])) {
8143 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
8144 return -1;
8145 }
8146 path = args[1];
8147
8148 if (*args[2]) {
8149 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
8150 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
8151 return -1;
8152 }
8153 type = args[2];
8154 }
8155
8156 return hlua_prepend_path(gL, type, path);
8157}
8158
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008159/* configuration keywords declaration */
8160static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008161 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008162 { CFG_GLOBAL, "lua-load", hlua_load },
8163 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
8164 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +02008165 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008166 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +01008167 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008168 { 0, NULL, NULL },
8169}};
8170
Willy Tarreau0108d902018-11-25 19:14:37 +01008171INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
8172
Christopher Fauletafd8f102018-11-08 11:34:21 +01008173
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008174/* This function can fail with an abort() due to an Lua critical error.
8175 * We are in the initialisation process of HAProxy, this abort() is
8176 * tolerated.
8177 */
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008178int hlua_post_init()
8179{
8180 struct hlua_init_function *init;
8181 const char *msg;
8182 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008183 const char *error;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008184
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05008185 /* Call post initialisation function in safe environment. */
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008186 if (!SET_SAFE_LJMP(gL.T)) {
8187 if (lua_type(gL.T, -1) == LUA_TSTRING)
8188 error = lua_tostring(gL.T, -1);
8189 else
8190 error = "critical error";
8191 fprintf(stderr, "Lua post-init: %s.\n", error);
8192 exit(1);
8193 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +02008194
8195#if USE_OPENSSL
8196 /* Initialize SSL server. */
8197 if (socket_ssl.xprt->prepare_srv) {
8198 int saved_used_backed = global.ssl_used_backend;
8199 // don't affect maxconn automatic computation
8200 socket_ssl.xprt->prepare_srv(&socket_ssl);
8201 global.ssl_used_backend = saved_used_backed;
8202 }
8203#endif
8204
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008205 hlua_fcn_post_init(gL.T);
8206 RESET_SAFE_LJMP(gL.T);
8207
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008208 list_for_each_entry(init, &hlua_init_functions, l) {
8209 lua_rawgeti(gL.T, LUA_REGISTRYINDEX, init->function_ref);
8210 ret = hlua_ctx_resume(&gL, 0);
8211 switch (ret) {
8212 case HLUA_E_OK:
8213 lua_pop(gL.T, -1);
Thierry Fournier5a964672020-11-28 11:02:58 +01008214 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008215 case HLUA_E_AGAIN:
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008216 ha_alert("Lua init: yield not allowed.\n");
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008217 return 0;
8218 case HLUA_E_ERRMSG:
8219 msg = lua_tostring(gL.T, -1);
Christopher Faulet767a84b2017-11-24 16:50:31 +01008220 ha_alert("lua init: %s.\n", msg);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008221 return 0;
8222 case HLUA_E_ERR:
8223 default:
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008224 ha_alert("Lua init: unknown runtime error.\n");
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008225 return 0;
8226 }
8227 }
8228 return 1;
8229}
8230
Willy Tarreau32f61e22015-03-18 17:54:59 +01008231/* The memory allocator used by the Lua stack. <ud> is a pointer to the
8232 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
8233 * is the previously allocated size or the kind of object in case of a new
8234 * allocation. <nsize> is the requested new size.
8235 */
8236static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
8237{
8238 struct hlua_mem_allocator *zone = ud;
8239
8240 if (nsize == 0) {
8241 /* it's a free */
8242 if (ptr)
8243 zone->allocated -= osize;
8244 free(ptr);
8245 return NULL;
8246 }
8247
8248 if (!ptr) {
8249 /* it's a new allocation */
8250 if (zone->limit && zone->allocated + nsize > zone->limit)
8251 return NULL;
8252
8253 ptr = malloc(nsize);
8254 if (ptr)
8255 zone->allocated += nsize;
8256 return ptr;
8257 }
8258
8259 /* it's a realloc */
8260 if (zone->limit && zone->allocated + nsize - osize > zone->limit)
8261 return NULL;
8262
8263 ptr = realloc(ptr, nsize);
8264 if (ptr)
8265 zone->allocated += nsize - osize;
8266 return ptr;
8267}
8268
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008269/* Ithis function can fail with an abort() due to an Lua critical error.
8270 * We are in the initialisation process of HAProxy, this abort() is
8271 * tolerated.
8272 */
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01008273void hlua_init(void)
8274{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008275 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008276 int idx;
8277 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008278 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008279 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008280 const char *error_msg;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008281#ifdef USE_OPENSSL
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008282 struct srv_kw *kw;
8283 int tmp_error;
8284 char *error;
Thierry FOURNIER36d13742015-03-17 16:48:53 +01008285 char *args[] = { /* SSL client configuration. */
8286 "ssl",
8287 "verify",
8288 "none",
Thierry FOURNIER36d13742015-03-17 16:48:53 +01008289 NULL
8290 };
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008291#endif
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008292
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008293 /* Init main lua stack. */
8294 gL.Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01008295 gL.flags = 0;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01008296 LIST_INIT(&gL.com);
Willy Tarreau42ef75f2017-04-12 21:40:29 +02008297 gL.T = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008298 hlua_sethlua(&gL);
8299 gL.Tref = LUA_REFNIL;
8300 gL.task = NULL;
8301
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008302 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008303 * the Lua function can fail with an abort. We are in the initialisation
8304 * process of HAProxy, this abort() is tolerated.
8305 */
8306
Thierry Fournier2b7983c2020-11-28 16:08:02 +01008307 /* Set safe environment for the initialisation. */
8308 if (!SET_SAFE_LJMP(gL.T)) {
8309 if (lua_type(gL.T, -1) == LUA_TSTRING)
8310 error_msg = lua_tostring(gL.T, -1);
8311 else
8312 error_msg = "critical error";
8313 fprintf(stderr, "Lua init: %s.\n", error_msg);
8314 exit(1);
8315 }
8316
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008317 /* Initialise lua. */
8318 luaL_openlibs(gL.T);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008319#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
8320#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
8321#ifdef HLUA_PREPEND_PATH
8322 hlua_prepend_path(gL, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
8323#endif
8324#ifdef HLUA_PREPEND_CPATH
8325 hlua_prepend_path(gL, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
8326#endif
8327#undef HLUA_PREPEND_PATH_TOSTRING
8328#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008329
8330 /*
8331 *
8332 * Create "core" object.
8333 *
8334 */
8335
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +01008336 /* This table entry is the object "core" base. */
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008337 lua_newtable(gL.T);
8338
8339 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008340 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008341 hlua_class_const_int(gL.T, log_levels[i], i);
8342
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008343 /* Register special functions. */
8344 hlua_class_function(gL.T, "register_init", hlua_register_init);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01008345 hlua_class_function(gL.T, "register_task", hlua_register_task);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01008346 hlua_class_function(gL.T, "register_fetches", hlua_register_fetches);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01008347 hlua_class_function(gL.T, "register_converters", hlua_register_converters);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008348 hlua_class_function(gL.T, "register_action", hlua_register_action);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008349 hlua_class_function(gL.T, "register_service", hlua_register_service);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008350 hlua_class_function(gL.T, "register_cli", hlua_register_cli);
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01008351 hlua_class_function(gL.T, "yield", hlua_yield);
Willy Tarreau59551662015-03-10 14:23:13 +01008352 hlua_class_function(gL.T, "set_nice", hlua_set_nice);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01008353 hlua_class_function(gL.T, "sleep", hlua_sleep);
8354 hlua_class_function(gL.T, "msleep", hlua_msleep);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01008355 hlua_class_function(gL.T, "add_acl", hlua_add_acl);
8356 hlua_class_function(gL.T, "del_acl", hlua_del_acl);
8357 hlua_class_function(gL.T, "set_map", hlua_set_map);
8358 hlua_class_function(gL.T, "del_map", hlua_del_map);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008359 hlua_class_function(gL.T, "tcp", hlua_socket_new);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01008360 hlua_class_function(gL.T, "log", hlua_log);
8361 hlua_class_function(gL.T, "Debug", hlua_log_debug);
8362 hlua_class_function(gL.T, "Info", hlua_log_info);
8363 hlua_class_function(gL.T, "Warning", hlua_log_warning);
8364 hlua_class_function(gL.T, "Alert", hlua_log_alert);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02008365 hlua_class_function(gL.T, "done", hlua_done);
Thierry Fournierfb0b5462016-01-21 09:28:58 +01008366 hlua_fcn_reg_core_fcn(gL.T);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008367
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008368 lua_setglobal(gL.T, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008369
8370 /*
8371 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008372 * Create "act" object.
8373 *
8374 */
8375
8376 /* This table entry is the object "act" base. */
8377 lua_newtable(gL.T);
8378
8379 /* push action return constants */
8380 hlua_class_const_int(gL.T, "CONTINUE", ACT_RET_CONT);
8381 hlua_class_const_int(gL.T, "STOP", ACT_RET_STOP);
8382 hlua_class_const_int(gL.T, "YIELD", ACT_RET_YIELD);
8383 hlua_class_const_int(gL.T, "ERROR", ACT_RET_ERR);
8384 hlua_class_const_int(gL.T, "DONE", ACT_RET_DONE);
8385 hlua_class_const_int(gL.T, "DENY", ACT_RET_DENY);
8386 hlua_class_const_int(gL.T, "ABORT", ACT_RET_ABRT);
8387 hlua_class_const_int(gL.T, "INVALID", ACT_RET_INV);
8388
Christopher Faulet501465d2020-02-26 14:54:16 +01008389 hlua_class_function(gL.T, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01008390
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008391 lua_setglobal(gL.T, "act");
8392
8393 /*
8394 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008395 * Register class Map
8396 *
8397 */
8398
8399 /* This table entry is the object "Map" base. */
8400 lua_newtable(gL.T);
8401
8402 /* register pattern types. */
8403 for (i=0; i<PAT_MATCH_NUM; i++)
8404 hlua_class_const_int(gL.T, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01008405 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008406 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
8407 hlua_class_const_int(gL.T, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01008408 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008409
8410 /* register constructor. */
8411 hlua_class_function(gL.T, "new", hlua_map_new);
8412
8413 /* Create and fill the metatable. */
8414 lua_newtable(gL.T);
8415
Ilya Shipitsind4259502020-04-08 01:07:56 +05008416 /* Create and fill the __index entry. */
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008417 lua_pushstring(gL.T, "__index");
8418 lua_newtable(gL.T);
8419
8420 /* Register . */
8421 hlua_class_function(gL.T, "lookup", hlua_map_lookup);
8422 hlua_class_function(gL.T, "slookup", hlua_map_slookup);
8423
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008424 lua_rawset(gL.T, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008425
Thierry Fournier45e78d72016-02-19 18:34:46 +01008426 /* Register previous table in the registry with reference and named entry.
8427 * The function hlua_register_metatable() pops the stack, so we
8428 * previously create a copy of the table.
8429 */
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008430 lua_pushvalue(gL.T, -1); /* Copy the -1 entry and push it on the stack. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008431 class_map_ref = hlua_register_metatable(gL.T, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008432
8433 /* Assign the metatable to the mai Map object. */
8434 lua_setmetatable(gL.T, -2);
8435
8436 /* Set a name to the table. */
8437 lua_setglobal(gL.T, "Map");
8438
8439 /*
8440 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008441 * Register class Channel
8442 *
8443 */
8444
8445 /* Create and fill the metatable. */
8446 lua_newtable(gL.T);
8447
Ilya Shipitsind4259502020-04-08 01:07:56 +05008448 /* Create and fill the __index entry. */
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008449 lua_pushstring(gL.T, "__index");
8450 lua_newtable(gL.T);
8451
8452 /* Register . */
8453 hlua_class_function(gL.T, "get", hlua_channel_get);
8454 hlua_class_function(gL.T, "dup", hlua_channel_dup);
8455 hlua_class_function(gL.T, "getline", hlua_channel_getline);
8456 hlua_class_function(gL.T, "set", hlua_channel_set);
8457 hlua_class_function(gL.T, "append", hlua_channel_append);
8458 hlua_class_function(gL.T, "send", hlua_channel_send);
8459 hlua_class_function(gL.T, "forward", hlua_channel_forward);
8460 hlua_class_function(gL.T, "get_in_len", hlua_channel_get_in_len);
8461 hlua_class_function(gL.T, "get_out_len", hlua_channel_get_out_len);
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01008462 hlua_class_function(gL.T, "is_full", hlua_channel_is_full);
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01008463 hlua_class_function(gL.T, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008464
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008465 lua_rawset(gL.T, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008466
8467 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008468 class_channel_ref = hlua_register_metatable(gL.T, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008469
8470 /*
8471 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008472 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008473 *
8474 */
8475
8476 /* Create and fill the metatable. */
8477 lua_newtable(gL.T);
8478
Ilya Shipitsind4259502020-04-08 01:07:56 +05008479 /* Create and fill the __index entry. */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008480 lua_pushstring(gL.T, "__index");
8481 lua_newtable(gL.T);
8482
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008483 /* Browse existing fetches and create the associated
8484 * object method.
8485 */
8486 sf = NULL;
8487 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008488 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
8489 * by an underscore.
8490 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008491 strncpy(trash.area, sf->kw, trash.size);
8492 trash.area[trash.size - 1] = '\0';
8493 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008494 if (*p == '.' || *p == '-' || *p == '+')
8495 *p = '_';
8496
8497 /* Register the function. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008498 lua_pushstring(gL.T, trash.area);
Willy Tarreau2ec22742015-03-10 14:27:20 +01008499 lua_pushlightuserdata(gL.T, sf);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008500 lua_pushcclosure(gL.T, hlua_run_sample_fetch, 1);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008501 lua_rawset(gL.T, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008502 }
8503
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008504 lua_rawset(gL.T, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008505
8506 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008507 class_fetches_ref = hlua_register_metatable(gL.T, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008508
8509 /*
8510 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008511 * Register class Converters
8512 *
8513 */
8514
8515 /* Create and fill the metatable. */
8516 lua_newtable(gL.T);
8517
8518 /* Create and fill the __index entry. */
8519 lua_pushstring(gL.T, "__index");
8520 lua_newtable(gL.T);
8521
8522 /* Browse existing converters and create the associated
8523 * object method.
8524 */
8525 sc = NULL;
8526 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008527 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
8528 * by an underscore.
8529 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008530 strncpy(trash.area, sc->kw, trash.size);
8531 trash.area[trash.size - 1] = '\0';
8532 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008533 if (*p == '.' || *p == '-' || *p == '+')
8534 *p = '_';
8535
8536 /* Register the function. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008537 lua_pushstring(gL.T, trash.area);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008538 lua_pushlightuserdata(gL.T, sc);
8539 lua_pushcclosure(gL.T, hlua_run_sample_conv, 1);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008540 lua_rawset(gL.T, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008541 }
8542
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008543 lua_rawset(gL.T, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008544
8545 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008546 class_converters_ref = hlua_register_metatable(gL.T, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008547
8548 /*
8549 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008550 * Register class HTTP
8551 *
8552 */
8553
8554 /* Create and fill the metatable. */
8555 lua_newtable(gL.T);
8556
Ilya Shipitsind4259502020-04-08 01:07:56 +05008557 /* Create and fill the __index entry. */
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008558 lua_pushstring(gL.T, "__index");
8559 lua_newtable(gL.T);
8560
8561 /* Register Lua functions. */
8562 hlua_class_function(gL.T, "req_get_headers",hlua_http_req_get_headers);
8563 hlua_class_function(gL.T, "req_del_header", hlua_http_req_del_hdr);
8564 hlua_class_function(gL.T, "req_rep_header", hlua_http_req_rep_hdr);
8565 hlua_class_function(gL.T, "req_rep_value", hlua_http_req_rep_val);
8566 hlua_class_function(gL.T, "req_add_header", hlua_http_req_add_hdr);
8567 hlua_class_function(gL.T, "req_set_header", hlua_http_req_set_hdr);
8568 hlua_class_function(gL.T, "req_set_method", hlua_http_req_set_meth);
8569 hlua_class_function(gL.T, "req_set_path", hlua_http_req_set_path);
8570 hlua_class_function(gL.T, "req_set_query", hlua_http_req_set_query);
8571 hlua_class_function(gL.T, "req_set_uri", hlua_http_req_set_uri);
8572
8573 hlua_class_function(gL.T, "res_get_headers",hlua_http_res_get_headers);
8574 hlua_class_function(gL.T, "res_del_header", hlua_http_res_del_hdr);
8575 hlua_class_function(gL.T, "res_rep_header", hlua_http_res_rep_hdr);
8576 hlua_class_function(gL.T, "res_rep_value", hlua_http_res_rep_val);
8577 hlua_class_function(gL.T, "res_add_header", hlua_http_res_add_hdr);
8578 hlua_class_function(gL.T, "res_set_header", hlua_http_res_set_hdr);
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02008579 hlua_class_function(gL.T, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008580
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008581 lua_rawset(gL.T, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008582
8583 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008584 class_http_ref = hlua_register_metatable(gL.T, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01008585
8586 /*
8587 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008588 * Register class AppletTCP
8589 *
8590 */
8591
8592 /* Create and fill the metatable. */
8593 lua_newtable(gL.T);
8594
Ilya Shipitsind4259502020-04-08 01:07:56 +05008595 /* Create and fill the __index entry. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008596 lua_pushstring(gL.T, "__index");
8597 lua_newtable(gL.T);
8598
8599 /* Register Lua functions. */
Thierry FOURNIER / OZON.IO3e1d7912016-12-12 12:29:34 +01008600 hlua_class_function(gL.T, "getline", hlua_applet_tcp_getline);
8601 hlua_class_function(gL.T, "receive", hlua_applet_tcp_recv);
8602 hlua_class_function(gL.T, "send", hlua_applet_tcp_send);
8603 hlua_class_function(gL.T, "set_priv", hlua_applet_tcp_set_priv);
8604 hlua_class_function(gL.T, "get_priv", hlua_applet_tcp_get_priv);
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01008605 hlua_class_function(gL.T, "set_var", hlua_applet_tcp_set_var);
8606 hlua_class_function(gL.T, "unset_var", hlua_applet_tcp_unset_var);
8607 hlua_class_function(gL.T, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008608
8609 lua_settable(gL.T, -3);
8610
8611 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008612 class_applet_tcp_ref = hlua_register_metatable(gL.T, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008613
8614 /*
8615 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02008616 * Register class AppletHTTP
8617 *
8618 */
8619
8620 /* Create and fill the metatable. */
8621 lua_newtable(gL.T);
8622
Ilya Shipitsind4259502020-04-08 01:07:56 +05008623 /* Create and fill the __index entry. */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02008624 lua_pushstring(gL.T, "__index");
8625 lua_newtable(gL.T);
8626
8627 /* Register Lua functions. */
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01008628 hlua_class_function(gL.T, "set_priv", hlua_applet_http_set_priv);
8629 hlua_class_function(gL.T, "get_priv", hlua_applet_http_get_priv);
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01008630 hlua_class_function(gL.T, "set_var", hlua_applet_http_set_var);
8631 hlua_class_function(gL.T, "unset_var", hlua_applet_http_unset_var);
8632 hlua_class_function(gL.T, "get_var", hlua_applet_http_get_var);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02008633 hlua_class_function(gL.T, "getline", hlua_applet_http_getline);
8634 hlua_class_function(gL.T, "receive", hlua_applet_http_recv);
8635 hlua_class_function(gL.T, "send", hlua_applet_http_send);
8636 hlua_class_function(gL.T, "add_header", hlua_applet_http_addheader);
8637 hlua_class_function(gL.T, "set_status", hlua_applet_http_status);
8638 hlua_class_function(gL.T, "start_response", hlua_applet_http_start_response);
8639
8640 lua_settable(gL.T, -3);
8641
8642 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008643 class_applet_http_ref = hlua_register_metatable(gL.T, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02008644
8645 /*
8646 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008647 * Register class TXN
8648 *
8649 */
8650
8651 /* Create and fill the metatable. */
8652 lua_newtable(gL.T);
8653
Ilya Shipitsind4259502020-04-08 01:07:56 +05008654 /* Create and fill the __index entry. */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008655 lua_pushstring(gL.T, "__index");
8656 lua_newtable(gL.T);
8657
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01008658 /* Register Lua functions. */
Patrick Hemmer268a7072018-05-11 12:52:31 -04008659 hlua_class_function(gL.T, "set_priv", hlua_set_priv);
8660 hlua_class_function(gL.T, "get_priv", hlua_get_priv);
8661 hlua_class_function(gL.T, "set_var", hlua_set_var);
8662 hlua_class_function(gL.T, "unset_var", hlua_unset_var);
8663 hlua_class_function(gL.T, "get_var", hlua_get_var);
8664 hlua_class_function(gL.T, "done", hlua_txn_done);
Christopher Faulet700d9e82020-01-31 12:21:52 +01008665 hlua_class_function(gL.T, "reply", hlua_txn_reply_new);
Patrick Hemmer268a7072018-05-11 12:52:31 -04008666 hlua_class_function(gL.T, "set_loglevel", hlua_txn_set_loglevel);
8667 hlua_class_function(gL.T, "set_tos", hlua_txn_set_tos);
8668 hlua_class_function(gL.T, "set_mark", hlua_txn_set_mark);
8669 hlua_class_function(gL.T, "set_priority_class", hlua_txn_set_priority_class);
8670 hlua_class_function(gL.T, "set_priority_offset", hlua_txn_set_priority_offset);
8671 hlua_class_function(gL.T, "deflog", hlua_txn_deflog);
8672 hlua_class_function(gL.T, "log", hlua_txn_log);
8673 hlua_class_function(gL.T, "Debug", hlua_txn_log_debug);
8674 hlua_class_function(gL.T, "Info", hlua_txn_log_info);
8675 hlua_class_function(gL.T, "Warning", hlua_txn_log_warning);
8676 hlua_class_function(gL.T, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01008677
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008678 lua_rawset(gL.T, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008679
8680 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008681 class_txn_ref = hlua_register_metatable(gL.T, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008682
8683 /*
8684 *
Christopher Faulet700d9e82020-01-31 12:21:52 +01008685 * Register class reply
8686 *
8687 */
8688 lua_newtable(gL.T);
8689 lua_pushstring(gL.T, "__index");
8690 lua_newtable(gL.T);
8691 hlua_class_function(gL.T, "set_status", hlua_txn_reply_set_status);
8692 hlua_class_function(gL.T, "add_header", hlua_txn_reply_add_header);
8693 hlua_class_function(gL.T, "del_header", hlua_txn_reply_del_header);
8694 hlua_class_function(gL.T, "set_body", hlua_txn_reply_set_body);
8695 lua_settable(gL.T, -3); /* Sets the __index entry. */
8696 class_txn_reply_ref = luaL_ref(gL.T, LUA_REGISTRYINDEX);
8697
8698
8699 /*
8700 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008701 * Register class Socket
8702 *
8703 */
8704
8705 /* Create and fill the metatable. */
8706 lua_newtable(gL.T);
8707
Ilya Shipitsind4259502020-04-08 01:07:56 +05008708 /* Create and fill the __index entry. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008709 lua_pushstring(gL.T, "__index");
8710 lua_newtable(gL.T);
8711
Baptiste Assmann84bb4932015-03-02 21:40:06 +01008712#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008713 hlua_class_function(gL.T, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +01008714#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008715 hlua_class_function(gL.T, "connect", hlua_socket_connect);
8716 hlua_class_function(gL.T, "send", hlua_socket_send);
8717 hlua_class_function(gL.T, "receive", hlua_socket_receive);
8718 hlua_class_function(gL.T, "close", hlua_socket_close);
8719 hlua_class_function(gL.T, "getpeername", hlua_socket_getpeername);
8720 hlua_class_function(gL.T, "getsockname", hlua_socket_getsockname);
8721 hlua_class_function(gL.T, "setoption", hlua_socket_setoption);
8722 hlua_class_function(gL.T, "settimeout", hlua_socket_settimeout);
8723
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008724 lua_rawset(gL.T, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008725
8726 /* Register the garbage collector entry. */
8727 lua_pushstring(gL.T, "__gc");
8728 lua_pushcclosure(gL.T, hlua_socket_gc, 0);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02008729 lua_rawset(gL.T, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008730
8731 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier45e78d72016-02-19 18:34:46 +01008732 class_socket_ref = hlua_register_metatable(gL.T, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008733
8734 /* Proxy and server configuration initialisation. */
8735 memset(&socket_proxy, 0, sizeof(socket_proxy));
8736 init_new_proxy(&socket_proxy);
8737 socket_proxy.parent = NULL;
8738 socket_proxy.last_change = now.tv_sec;
8739 socket_proxy.id = "LUA-SOCKET";
8740 socket_proxy.cap = PR_CAP_FE | PR_CAP_BE;
8741 socket_proxy.maxconn = 0;
8742 socket_proxy.accept = NULL;
8743 socket_proxy.options2 |= PR_O2_INDEPSTR;
8744 socket_proxy.srv = NULL;
8745 socket_proxy.conn_retries = 0;
8746 socket_proxy.timeout.connect = 5000; /* By default the timeout connection is 5s. */
8747
8748 /* Init TCP server: unchanged parameters */
8749 memset(&socket_tcp, 0, sizeof(socket_tcp));
8750 socket_tcp.next = NULL;
8751 socket_tcp.proxy = &socket_proxy;
8752 socket_tcp.obj_type = OBJ_TYPE_SERVER;
Willy Tarreau72653c52021-03-04 10:47:54 +01008753 for (i = 0; i < MAX_THREADS; i++)
8754 MT_LIST_INIT(&socket_tcp.actconns[i]);
Patrick Hemmer0355dab2018-05-11 12:52:31 -04008755 socket_tcp.pendconns = EB_ROOT;
Christopher Faulet40a007c2017-07-03 15:41:01 +02008756 socket_tcp.idle_conns = NULL;
8757 socket_tcp.safe_conns = NULL;
Emeric Brun52a91d32017-08-31 14:41:55 +02008758 socket_tcp.next_state = SRV_ST_RUNNING; /* early server setup */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008759 socket_tcp.last_change = 0;
8760 socket_tcp.id = "LUA-TCP-CONN";
8761 socket_tcp.check.state &= ~CHK_ST_ENABLED; /* Disable health checks. */
8762 socket_tcp.agent.state &= ~CHK_ST_ENABLED; /* Disable health checks. */
8763 socket_tcp.pp_opts = 0; /* Remove proxy protocol. */
8764
8765 /* XXX: Copy default parameter from default server,
8766 * but the default server is not initialized.
8767 */
8768 socket_tcp.maxqueue = socket_proxy.defsrv.maxqueue;
8769 socket_tcp.minconn = socket_proxy.defsrv.minconn;
8770 socket_tcp.maxconn = socket_proxy.defsrv.maxconn;
8771 socket_tcp.slowstart = socket_proxy.defsrv.slowstart;
8772 socket_tcp.onerror = socket_proxy.defsrv.onerror;
8773 socket_tcp.onmarkeddown = socket_proxy.defsrv.onmarkeddown;
8774 socket_tcp.onmarkedup = socket_proxy.defsrv.onmarkedup;
8775 socket_tcp.consecutive_errors_limit = socket_proxy.defsrv.consecutive_errors_limit;
8776 socket_tcp.uweight = socket_proxy.defsrv.iweight;
8777 socket_tcp.iweight = socket_proxy.defsrv.iweight;
8778
8779 socket_tcp.check.status = HCHK_STATUS_INI;
8780 socket_tcp.check.rise = socket_proxy.defsrv.check.rise;
8781 socket_tcp.check.fall = socket_proxy.defsrv.check.fall;
8782 socket_tcp.check.health = socket_tcp.check.rise; /* socket, but will fall down at first failure */
8783 socket_tcp.check.server = &socket_tcp;
8784
8785 socket_tcp.agent.status = HCHK_STATUS_INI;
8786 socket_tcp.agent.rise = socket_proxy.defsrv.agent.rise;
8787 socket_tcp.agent.fall = socket_proxy.defsrv.agent.fall;
8788 socket_tcp.agent.health = socket_tcp.agent.rise; /* socket, but will fall down at first failure */
8789 socket_tcp.agent.server = &socket_tcp;
8790
Willy Tarreaua261e9b2016-12-22 20:44:00 +01008791 socket_tcp.xprt = xprt_get(XPRT_RAW);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008792
8793#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008794 /* Init TCP server: unchanged parameters */
8795 memset(&socket_ssl, 0, sizeof(socket_ssl));
8796 socket_ssl.next = NULL;
8797 socket_ssl.proxy = &socket_proxy;
8798 socket_ssl.obj_type = OBJ_TYPE_SERVER;
Willy Tarreau72653c52021-03-04 10:47:54 +01008799 for (i = 0; i < MAX_THREADS; i++)
8800 MT_LIST_INIT(&socket_ssl.actconns[i]);
Patrick Hemmer0355dab2018-05-11 12:52:31 -04008801 socket_ssl.pendconns = EB_ROOT;
Willy Tarreaub784b352019-02-07 14:48:24 +01008802 socket_ssl.idle_conns = NULL;
8803 socket_ssl.safe_conns = NULL;
Emeric Brun52a91d32017-08-31 14:41:55 +02008804 socket_ssl.next_state = SRV_ST_RUNNING; /* early server setup */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008805 socket_ssl.last_change = 0;
8806 socket_ssl.id = "LUA-SSL-CONN";
8807 socket_ssl.check.state &= ~CHK_ST_ENABLED; /* Disable health checks. */
8808 socket_ssl.agent.state &= ~CHK_ST_ENABLED; /* Disable health checks. */
8809 socket_ssl.pp_opts = 0; /* Remove proxy protocol. */
8810
8811 /* XXX: Copy default parameter from default server,
8812 * but the default server is not initialized.
8813 */
8814 socket_ssl.maxqueue = socket_proxy.defsrv.maxqueue;
8815 socket_ssl.minconn = socket_proxy.defsrv.minconn;
8816 socket_ssl.maxconn = socket_proxy.defsrv.maxconn;
8817 socket_ssl.slowstart = socket_proxy.defsrv.slowstart;
8818 socket_ssl.onerror = socket_proxy.defsrv.onerror;
8819 socket_ssl.onmarkeddown = socket_proxy.defsrv.onmarkeddown;
8820 socket_ssl.onmarkedup = socket_proxy.defsrv.onmarkedup;
8821 socket_ssl.consecutive_errors_limit = socket_proxy.defsrv.consecutive_errors_limit;
8822 socket_ssl.uweight = socket_proxy.defsrv.iweight;
8823 socket_ssl.iweight = socket_proxy.defsrv.iweight;
8824
8825 socket_ssl.check.status = HCHK_STATUS_INI;
8826 socket_ssl.check.rise = socket_proxy.defsrv.check.rise;
8827 socket_ssl.check.fall = socket_proxy.defsrv.check.fall;
8828 socket_ssl.check.health = socket_ssl.check.rise; /* socket, but will fall down at first failure */
8829 socket_ssl.check.server = &socket_ssl;
8830
8831 socket_ssl.agent.status = HCHK_STATUS_INI;
8832 socket_ssl.agent.rise = socket_proxy.defsrv.agent.rise;
8833 socket_ssl.agent.fall = socket_proxy.defsrv.agent.fall;
8834 socket_ssl.agent.health = socket_ssl.agent.rise; /* socket, but will fall down at first failure */
8835 socket_ssl.agent.server = &socket_ssl;
8836
Thierry FOURNIER36d13742015-03-17 16:48:53 +01008837 socket_ssl.use_ssl = 1;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01008838 socket_ssl.xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008839
Thierry FOURNIER36d13742015-03-17 16:48:53 +01008840 for (idx = 0; args[idx] != NULL; idx++) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008841 if ((kw = srv_find_kw(args[idx])) != NULL) { /* Maybe it's registered server keyword */
8842 /*
8843 *
8844 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008845 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008846 * features like client certificates and ssl_verify.
8847 *
8848 */
8849 tmp_error = kw->parse(args, &idx, &socket_proxy, &socket_ssl, &error);
8850 if (tmp_error != 0) {
8851 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
8852 abort(); /* This must be never arrives because the command line
8853 not editable by the user. */
8854 }
8855 idx += kw->skip;
8856 }
8857 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01008858#endif
Thierry Fournier75933d42016-01-21 09:30:18 +01008859
8860 RESET_SAFE_LJMP(gL.T);
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01008861}
Willy Tarreaubb57d942016-12-21 19:04:56 +01008862
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +02008863static void hlua_deinit()
8864{
8865 lua_close(gL.T);
8866}
8867
8868REGISTER_POST_DEINIT(hlua_deinit);
8869
Willy Tarreau80713382018-11-26 10:19:54 +01008870static void hlua_register_build_options(void)
8871{
Willy Tarreaubb57d942016-12-21 19:04:56 +01008872 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +01008873
Willy Tarreaubb57d942016-12-21 19:04:56 +01008874 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
8875 hap_register_build_opts(ptr, 1);
8876}
Willy Tarreau80713382018-11-26 10:19:54 +01008877
8878INITCALL0(STG_REGISTER, hlua_register_build_options);