blob: a7d02e57ab738cefc3a8ae6241e7b242e49afa3b [file] [log] [blame]
Emeric Brun107ca302010-01-04 16:16:05 +01001/*
Willy Tarreaucd3b0942012-04-27 21:52:18 +02002 * Sample management functions.
Emeric Brun107ca302010-01-04 16:16:05 +01003 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
Willy Tarreaucd3b0942012-04-27 21:52:18 +02005 * Copyright (C) 2012 Willy Tarreau <w@1wt.eu>
Emeric Brun107ca302010-01-04 16:16:05 +01006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <string.h>
15#include <arpa/inet.h>
Willy Tarreaudd2f85e2012-09-02 22:34:23 +020016#include <stdio.h>
Emeric Brun107ca302010-01-04 16:16:05 +010017
Willy Tarreau7e2c6472012-10-29 20:44:36 +010018#include <types/global.h>
19
Willy Tarreauc7e42382012-08-24 19:22:53 +020020#include <common/chunk.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020021#include <common/standard.h>
22
Willy Tarreau9fcb9842012-04-20 14:45:49 +020023#include <proto/arg.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020024#include <proto/sample.h>
Emeric Brun107ca302010-01-04 16:16:05 +010025
Willy Tarreau12785782012-04-27 21:37:17 +020026/* static sample used in sample_process() when <p> is NULL */
Willy Tarreaub4a88f02012-04-23 21:35:11 +020027static struct sample temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +010028
Willy Tarreau12785782012-04-27 21:37:17 +020029/* trash chunk used for sample conversions */
Emeric Brun107ca302010-01-04 16:16:05 +010030static struct chunk trash_chunk;
31
Willy Tarreau12785782012-04-27 21:37:17 +020032/* trash buffers used or sample conversions */
Willy Tarreau7e2c6472012-10-29 20:44:36 +010033char *sample_trash_buf1;
34char *sample_trash_buf2;
Emeric Brun107ca302010-01-04 16:16:05 +010035
Willy Tarreau12785782012-04-27 21:37:17 +020036/* list head of all known sample fetch keywords */
37static struct sample_fetch_kw_list sample_fetches = {
38 .list = LIST_HEAD_INIT(sample_fetches.list)
Emeric Brun107ca302010-01-04 16:16:05 +010039};
40
Willy Tarreau12785782012-04-27 21:37:17 +020041/* list head of all known sample format conversion keywords */
42static struct sample_conv_kw_list sample_convs = {
43 .list = LIST_HEAD_INIT(sample_convs.list)
Emeric Brun107ca302010-01-04 16:16:05 +010044};
45
46/*
Willy Tarreau12785782012-04-27 21:37:17 +020047 * Registers the sample fetch keyword list <kwl> as a list of valid keywords for next
Emeric Brun107ca302010-01-04 16:16:05 +010048 * parsing sessions.
49 */
Willy Tarreau12785782012-04-27 21:37:17 +020050void sample_register_fetches(struct sample_fetch_kw_list *pfkl)
Emeric Brun107ca302010-01-04 16:16:05 +010051{
Willy Tarreau12785782012-04-27 21:37:17 +020052 LIST_ADDQ(&sample_fetches.list, &pfkl->list);
Emeric Brun107ca302010-01-04 16:16:05 +010053}
54
55/*
Willy Tarreau12785782012-04-27 21:37:17 +020056 * Registers the sample format coverstion keyword list <pckl> as a list of valid keywords for next
Emeric Brun107ca302010-01-04 16:16:05 +010057 * parsing sessions.
58 */
Willy Tarreau12785782012-04-27 21:37:17 +020059void sample_register_convs(struct sample_conv_kw_list *pckl)
Emeric Brun107ca302010-01-04 16:16:05 +010060{
Willy Tarreau12785782012-04-27 21:37:17 +020061 LIST_ADDQ(&sample_convs.list, &pckl->list);
Emeric Brun107ca302010-01-04 16:16:05 +010062}
63
64/*
Willy Tarreau12785782012-04-27 21:37:17 +020065 * Returns the pointer on sample fetch keyword structure identified by
Emeric Brun107ca302010-01-04 16:16:05 +010066 * string of <len> in buffer <kw>.
67 *
68 */
Willy Tarreau12785782012-04-27 21:37:17 +020069struct sample_fetch *find_sample_fetch(const char *kw, int len)
Emeric Brun107ca302010-01-04 16:16:05 +010070{
71 int index;
Willy Tarreau12785782012-04-27 21:37:17 +020072 struct sample_fetch_kw_list *kwl;
Emeric Brun107ca302010-01-04 16:16:05 +010073
Willy Tarreau12785782012-04-27 21:37:17 +020074 list_for_each_entry(kwl, &sample_fetches.list, list) {
Emeric Brun107ca302010-01-04 16:16:05 +010075 for (index = 0; kwl->kw[index].kw != NULL; index++) {
76 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
77 kwl->kw[index].kw[len] == '\0')
78 return &kwl->kw[index];
79 }
80 }
81 return NULL;
82}
83
84/*
Willy Tarreau12785782012-04-27 21:37:17 +020085 * Returns the pointer on sample format conversion keyword structure identified by
Emeric Brun107ca302010-01-04 16:16:05 +010086 * string of <len> in buffer <kw>.
87 *
88 */
Willy Tarreau12785782012-04-27 21:37:17 +020089struct sample_conv *find_sample_conv(const char *kw, int len)
Emeric Brun107ca302010-01-04 16:16:05 +010090{
91 int index;
Willy Tarreau12785782012-04-27 21:37:17 +020092 struct sample_conv_kw_list *kwl;
Emeric Brun107ca302010-01-04 16:16:05 +010093
Willy Tarreau12785782012-04-27 21:37:17 +020094 list_for_each_entry(kwl, &sample_convs.list, list) {
Emeric Brun107ca302010-01-04 16:16:05 +010095 for (index = 0; kwl->kw[index].kw != NULL; index++) {
96 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
97 kwl->kw[index].kw[len] == '\0')
98 return &kwl->kw[index];
99 }
100 }
101 return NULL;
102}
103
104
105/*
Willy Tarreau12785782012-04-27 21:37:17 +0200106* Returns a static trash struct chunk to use in sample casts or format conversions
Emeric Brun107ca302010-01-04 16:16:05 +0100107* Swiths the 2 available trash buffers to protect data during convert
108*/
Emeric Bruna068a292012-10-17 15:34:03 +0200109struct chunk *sample_get_trash_chunk(void)
Emeric Brun107ca302010-01-04 16:16:05 +0100110{
Willy Tarreau7e2c6472012-10-29 20:44:36 +0100111 char *sample_trash_buf;
112
113 sample_trash_buf = sample_trash_buf1;
114 sample_trash_buf1 = sample_trash_buf2;
115 sample_trash_buf2 = sample_trash_buf1;
Emeric Brun107ca302010-01-04 16:16:05 +0100116
Willy Tarreau7e2c6472012-10-29 20:44:36 +0100117 chunk_init(&trash_chunk, sample_trash_buf, global.tune.bufsize);
Emeric Brun107ca302010-01-04 16:16:05 +0100118
119 return &trash_chunk;
120}
121
Emeric Brun107ca302010-01-04 16:16:05 +0100122/******************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200123/* Sample casts functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200124/* Note: these functions do *NOT* set the output type on the */
125/* sample, the caller is responsible for doing this on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100126/******************************************************************/
127
Willy Tarreau342acb42012-04-23 22:03:39 +0200128static int c_ip2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100129{
Willy Tarreau342acb42012-04-23 22:03:39 +0200130 smp->data.uint = ntohl(smp->data.ipv4.s_addr);
Emeric Brun107ca302010-01-04 16:16:05 +0100131 return 1;
132}
133
Willy Tarreau342acb42012-04-23 22:03:39 +0200134static int c_ip2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100135{
Emeric Bruna068a292012-10-17 15:34:03 +0200136 struct chunk *trash = sample_get_trash_chunk();
Emeric Brun107ca302010-01-04 16:16:05 +0100137
Willy Tarreau342acb42012-04-23 22:03:39 +0200138 if (!inet_ntop(AF_INET, (void *)&smp->data.ipv4, trash->str, trash->size))
Emeric Brun107ca302010-01-04 16:16:05 +0100139 return 0;
140
141 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200142 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100143
144 return 1;
145}
146
Willy Tarreau342acb42012-04-23 22:03:39 +0200147static int c_ip2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100148{
Willy Tarreau342acb42012-04-23 22:03:39 +0200149 v4tov6(&smp->data.ipv6, &smp->data.ipv4);
David du Colombier4f92d322011-03-24 11:09:31 +0100150 return 1;
151}
152
Willy Tarreau342acb42012-04-23 22:03:39 +0200153static int c_ipv62str(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100154{
Emeric Bruna068a292012-10-17 15:34:03 +0200155 struct chunk *trash = sample_get_trash_chunk();
David du Colombier4f92d322011-03-24 11:09:31 +0100156
Willy Tarreau342acb42012-04-23 22:03:39 +0200157 if (!inet_ntop(AF_INET6, (void *)&smp->data.ipv6, trash->str, trash->size))
David du Colombier4f92d322011-03-24 11:09:31 +0100158 return 0;
159
160 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200161 smp->data.str = *trash;
David du Colombier4f92d322011-03-24 11:09:31 +0100162 return 1;
163}
164
165/*
Willy Tarreau342acb42012-04-23 22:03:39 +0200166static int c_ipv62ip(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100167{
Willy Tarreau342acb42012-04-23 22:03:39 +0200168 return v6tov4(&smp->data.ipv4, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100169}
170*/
171
Willy Tarreau342acb42012-04-23 22:03:39 +0200172static int c_int2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100173{
Willy Tarreau342acb42012-04-23 22:03:39 +0200174 smp->data.ipv4.s_addr = htonl(smp->data.uint);
Emeric Brun107ca302010-01-04 16:16:05 +0100175 return 1;
176}
177
Willy Tarreau342acb42012-04-23 22:03:39 +0200178static int c_str2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100179{
Willy Tarreau342acb42012-04-23 22:03:39 +0200180 if (!buf2ip(smp->data.str.str, smp->data.str.len, &smp->data.ipv4))
Emeric Brun107ca302010-01-04 16:16:05 +0100181 return 0;
182 return 1;
183}
184
Willy Tarreau342acb42012-04-23 22:03:39 +0200185static int c_str2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100186{
Willy Tarreau342acb42012-04-23 22:03:39 +0200187 return inet_pton(AF_INET6, smp->data.str.str, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100188}
189
Emeric Brun8ac33d92012-10-17 13:36:06 +0200190static int c_bin2str(struct sample *smp)
191{
Emeric Bruna068a292012-10-17 15:34:03 +0200192 struct chunk *trash = sample_get_trash_chunk();
Emeric Brun8ac33d92012-10-17 13:36:06 +0200193 unsigned char c;
194 int ptr = 0;
195
196 trash->len = 0;
197 while (ptr < smp->data.str.len && trash->len <= trash->size - 2) {
198 c = smp->data.str.str[ptr++];
199 trash->str[trash->len++] = hextab[(c >> 4) & 0xF];
200 trash->str[trash->len++] = hextab[c & 0xF];
201 }
202 smp->data.str = *trash;
203 return 1;
204}
205
Willy Tarreau342acb42012-04-23 22:03:39 +0200206static int c_int2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100207{
Emeric Bruna068a292012-10-17 15:34:03 +0200208 struct chunk *trash = sample_get_trash_chunk();
Emeric Brun107ca302010-01-04 16:16:05 +0100209 char *pos;
210
Willy Tarreau342acb42012-04-23 22:03:39 +0200211 pos = ultoa_r(smp->data.uint, trash->str, trash->size);
Emeric Brun107ca302010-01-04 16:16:05 +0100212
213 if (!pos)
214 return 0;
215
Emeric Brun485479d2010-09-23 18:02:19 +0200216 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100217 trash->str = pos;
218 trash->len = strlen(pos);
Willy Tarreau342acb42012-04-23 22:03:39 +0200219 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100220 return 1;
221}
222
Willy Tarreau342acb42012-04-23 22:03:39 +0200223static int c_datadup(struct sample *smp)
Emeric Brun485479d2010-09-23 18:02:19 +0200224{
Emeric Bruna068a292012-10-17 15:34:03 +0200225 struct chunk *trash = sample_get_trash_chunk();
Emeric Brun485479d2010-09-23 18:02:19 +0200226
Willy Tarreau342acb42012-04-23 22:03:39 +0200227 trash->len = smp->data.str.len < trash->size ? smp->data.str.len : trash->size;
228 memcpy(trash->str, smp->data.str.str, trash->len);
229 smp->data.str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200230 return 1;
231}
232
233
Willy Tarreau342acb42012-04-23 22:03:39 +0200234static int c_none(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100235{
236 return 1;
237}
238
Willy Tarreau342acb42012-04-23 22:03:39 +0200239static int c_str2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100240{
241 int i;
242 uint32_t ret = 0;
243
Willy Tarreau342acb42012-04-23 22:03:39 +0200244 for (i = 0; i < smp->data.str.len; i++) {
245 uint32_t val = smp->data.str.str[i] - '0';
Emeric Brun107ca302010-01-04 16:16:05 +0100246
247 if (val > 9)
248 break;
249
250 ret = ret * 10 + val;
251 }
252
Willy Tarreau342acb42012-04-23 22:03:39 +0200253 smp->data.uint = ret;
Emeric Brun107ca302010-01-04 16:16:05 +0100254 return 1;
255}
256
257/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200258/* Sample casts matrix: */
259/* sample_casts[from type][to type] */
260/* NULL pointer used for impossible sample casts */
Emeric Brun107ca302010-01-04 16:16:05 +0100261/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100262
Willy Tarreau12785782012-04-27 21:37:17 +0200263typedef int (*sample_cast_fct)(struct sample *smp);
264static sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
Willy Tarreau422aa072012-04-20 20:49:27 +0200265/* to: BOOL UINT SINT IPV4 IPV6 STR BIN CSTR CBIN */
266/* from: BOOL */ { c_none, c_none, c_none, NULL, NULL, NULL, NULL, NULL, NULL },
267/* UINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
268/* SINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
269/* IPV4 */ { NULL, c_ip2int, c_ip2int, c_none, c_ip2ipv6, c_ip2str, NULL, c_ip2str, NULL },
270/* IPV6 */ { NULL, NULL, NULL, NULL, c_none, c_ipv62str, NULL, c_ipv62str, NULL },
271/* STR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_none, c_none, c_none, c_none },
Emeric Brun8ac33d92012-10-17 13:36:06 +0200272/* BIN */ { NULL, NULL, NULL, NULL, NULL, c_bin2str, c_none, c_bin2str, c_none },
Willy Tarreau422aa072012-04-20 20:49:27 +0200273/* CSTR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_datadup, c_datadup, c_none, c_none },
Emeric Brun8ac33d92012-10-17 13:36:06 +0200274/* CBIN */ { NULL, NULL, NULL, NULL, NULL, c_bin2str, c_datadup, c_bin2str, c_none },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200275};
Emeric Brun107ca302010-01-04 16:16:05 +0100276
Emeric Brun107ca302010-01-04 16:16:05 +0100277/*
Willy Tarreau12785782012-04-27 21:37:17 +0200278 * Parse a sample expression configuration:
Emeric Brun107ca302010-01-04 16:16:05 +0100279 * fetch keyword followed by format conversion keywords.
Willy Tarreau12785782012-04-27 21:37:17 +0200280 * Returns a pointer on allocated sample expression structure.
Emeric Brun107ca302010-01-04 16:16:05 +0100281 */
Willy Tarreau12785782012-04-27 21:37:17 +0200282struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100283{
284 const char *endw;
285 const char *end;
Willy Tarreau12785782012-04-27 21:37:17 +0200286 struct sample_expr *expr;
287 struct sample_fetch *fetch;
288 struct sample_conv *conv;
Emeric Brun107ca302010-01-04 16:16:05 +0100289 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200290 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100291
Emeric Brun485479d2010-09-23 18:02:19 +0200292 snprintf(err, err_size, "memory error.");
293 if (!str[*idx]) {
294
295 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100296 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200297 }
Emeric Brun107ca302010-01-04 16:16:05 +0100298
299 end = str[*idx] + strlen(str[*idx]);
300 endw = strchr(str[*idx], '(');
301
302 if (!endw)
303 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200304 else if ((end-1)[0] != ')') {
305 p = my_strndup(str[*idx], endw - str[*idx]);
306 if (p) {
307 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
308 free(p);
309 }
Emeric Brun107ca302010-01-04 16:16:05 +0100310 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200311 }
Emeric Brun107ca302010-01-04 16:16:05 +0100312
Willy Tarreau12785782012-04-27 21:37:17 +0200313 fetch = find_sample_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200314 if (!fetch) {
315 p = my_strndup(str[*idx], endw - str[*idx]);
316 if (p) {
317 snprintf(err, err_size, "unknown fetch method '%s'.", p);
318 free(p);
319 }
Emeric Brun107ca302010-01-04 16:16:05 +0100320 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200321 }
Willy Tarreau422aa072012-04-20 20:49:27 +0200322 if (fetch->out_type >= SMP_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100323
Emeric Brun485479d2010-09-23 18:02:19 +0200324 p = my_strndup(str[*idx], endw - str[*idx]);
325 if (p) {
326 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
327 free(p);
328 }
Emeric Brun107ca302010-01-04 16:16:05 +0100329 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200330 }
Emeric Brun107ca302010-01-04 16:16:05 +0100331
332 prev_type = fetch->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200333 expr = calloc(1, sizeof(struct sample_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200334 if (!expr)
335 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100336
337 LIST_INIT(&(expr->conv_exprs));
338 expr->fetch = fetch;
Willy Tarreau2e845be2012-10-19 19:49:09 +0200339 expr->arg_p = empty_arg_list;
Emeric Brun107ca302010-01-04 16:16:05 +0100340
341 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200342 char *err_msg = NULL;
343 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200344
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200345 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200346 p = my_strndup(str[*idx], endw - str[*idx]);
347 if (p) {
348 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
349 free(p);
350 }
351 goto out_error;
352 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200353
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200354 if (make_arg_list(endw + 1, end - endw - 2, fetch->arg_mask, &expr->arg_p, &err_msg, NULL, &err_arg) < 0) {
Emeric Brun485479d2010-09-23 18:02:19 +0200355 p = my_strndup(str[*idx], endw - str[*idx]);
356 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200357 snprintf(err, err_size, "invalid arg %d in fetch method '%s' : %s.", err_arg+1, p, err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200358 free(p);
359 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200360 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200361 goto out_error;
362 }
363
Willy Tarreau2e845be2012-10-19 19:49:09 +0200364 if (!expr->arg_p)
365 expr->arg_p = empty_arg_list;
366
Willy Tarreau21d68a62012-04-20 15:52:36 +0200367 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
368 p = my_strndup(str[*idx], endw - str[*idx]);
369 if (p) {
370 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
371 free(p);
372 }
373 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200374 goto out_error;
375 }
376 }
Willy Tarreauf22a5082012-10-19 16:47:23 +0200377 else if (ARGM(fetch->arg_mask)) {
Emeric Brun485479d2010-09-23 18:02:19 +0200378 p = my_strndup(str[*idx], endw - str[*idx]);
379 if (p) {
380 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
381 free(p);
382 }
383 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100384 }
385
386 for (*idx += 1; *(str[*idx]); (*idx)++) {
Willy Tarreau12785782012-04-27 21:37:17 +0200387 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100388
389 end = str[*idx] + strlen(str[*idx]);
390 endw = strchr(str[*idx], '(');
391
392 if (!endw)
393 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200394 else if ((end-1)[0] != ')') {
395 p = my_strndup(str[*idx], endw - str[*idx]);
396 if (p) {
397 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
398 free(p);
399 }
Emeric Brun107ca302010-01-04 16:16:05 +0100400 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200401 }
Emeric Brun107ca302010-01-04 16:16:05 +0100402
Willy Tarreau12785782012-04-27 21:37:17 +0200403 conv = find_sample_conv(str[*idx], endw - str[*idx]);
Emeric Brun107ca302010-01-04 16:16:05 +0100404 if (!conv)
405 break;
406
Willy Tarreau422aa072012-04-20 20:49:27 +0200407 if (conv->in_type >= SMP_TYPES ||
408 conv->out_type >= SMP_TYPES) {
Emeric Brun485479d2010-09-23 18:02:19 +0200409 p = my_strndup(str[*idx], endw - str[*idx]);
410 if (p) {
411 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
412 free(p);
413 }
Emeric Brun107ca302010-01-04 16:16:05 +0100414 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200415 }
Emeric Brun107ca302010-01-04 16:16:05 +0100416
417 /* If impossible type conversion */
Willy Tarreau12785782012-04-27 21:37:17 +0200418 if (!sample_casts[prev_type][conv->in_type]) {
Emeric Brun485479d2010-09-23 18:02:19 +0200419 p = my_strndup(str[*idx], endw - str[*idx]);
420 if (p) {
421 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
422 free(p);
423 }
Emeric Brun107ca302010-01-04 16:16:05 +0100424 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200425 }
Emeric Brun107ca302010-01-04 16:16:05 +0100426
427 prev_type = conv->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200428 conv_expr = calloc(1, sizeof(struct sample_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200429 if (!conv_expr)
430 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100431
432 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
433 conv_expr->conv = conv;
434
435 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200436 char *err_msg = NULL;
437 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200438
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200439 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200440 p = my_strndup(str[*idx], endw - str[*idx]);
441
442 if (p) {
443 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
444 free(p);
445 }
446 goto out_error;
447 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100448
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200449 if (make_arg_list(endw + 1, end - endw - 2, conv->arg_mask, &conv_expr->arg_p, &err_msg, NULL, &err_arg) < 0) {
Emeric Brun485479d2010-09-23 18:02:19 +0200450 p = my_strndup(str[*idx], endw - str[*idx]);
451 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200452 snprintf(err, err_size, "invalid arg %d in conv method '%s' : %s.", err_arg+1, p, err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200453 free(p);
454 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200455 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200456 goto out_error;
457 }
458
Willy Tarreau2e845be2012-10-19 19:49:09 +0200459 if (!conv_expr->arg_p)
460 conv_expr->arg_p = empty_arg_list;
461
Willy Tarreau21d68a62012-04-20 15:52:36 +0200462 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
463 p = my_strndup(str[*idx], endw - str[*idx]);
464 if (p) {
465 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
466 free(p);
467 }
468 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200469 goto out_error;
470 }
471 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200472 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200473 p = my_strndup(str[*idx], endw - str[*idx]);
474 if (p) {
475 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100476 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100477 }
Emeric Brun485479d2010-09-23 18:02:19 +0200478 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100479 }
Emeric Brun485479d2010-09-23 18:02:19 +0200480
Emeric Brun107ca302010-01-04 16:16:05 +0100481 }
Emeric Brun485479d2010-09-23 18:02:19 +0200482
Emeric Brun107ca302010-01-04 16:16:05 +0100483 return expr;
484
485out_error:
Willy Tarreau12785782012-04-27 21:37:17 +0200486 /* TODO: prune_sample_expr(expr); */
Emeric Brun107ca302010-01-04 16:16:05 +0100487 return NULL;
488}
489
490/*
Willy Tarreau12785782012-04-27 21:37:17 +0200491 * Process a fetch + format conversion of defined by the sample expression <expr>
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200492 * on request or response considering the <opt> parameter.
Willy Tarreau12785782012-04-27 21:37:17 +0200493 * Returns a pointer on a typed sample structure containing the result or NULL if
494 * sample is not found or when format conversion failed.
Emeric Brun107ca302010-01-04 16:16:05 +0100495 * If <p> is not null, function returns results in structure pointed by <p>.
Willy Tarreau12785782012-04-27 21:37:17 +0200496 * If <p> is null, functions returns a pointer on a static sample structure.
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200497 *
498 * Note: the fetch functions are required to properly set the return type. The
499 * conversion functions must do so too. However the cast functions do not need
500 * to since they're made to cast mutiple types according to what is required.
Emeric Brun107ca302010-01-04 16:16:05 +0100501 */
Willy Tarreau12785782012-04-27 21:37:17 +0200502struct sample *sample_process(struct proxy *px, struct session *l4, void *l7,
503 unsigned int opt,
504 struct sample_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100505{
Willy Tarreau12785782012-04-27 21:37:17 +0200506 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100507
508 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200509 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100510
Willy Tarreau342acb42012-04-23 22:03:39 +0200511 p->flags = 0;
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200512 if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100513 return NULL;
514
Willy Tarreau40aebd92012-04-26 11:05:50 +0200515 if (p->flags & SMP_F_MAY_CHANGE)
Willy Tarreau12785782012-04-27 21:37:17 +0200516 return NULL; /* we can only use stable samples */
Willy Tarreau40aebd92012-04-26 11:05:50 +0200517
Emeric Brun107ca302010-01-04 16:16:05 +0100518 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
Willy Tarreau12e50112012-04-25 17:21:49 +0200519 /* we want to ensure that p->type can be casted into
520 * conv_expr->conv->in_type. We have 3 possibilities :
521 * - NULL => not castable.
522 * - c_none => nothing to do (let's optimize it)
523 * - other => apply cast and prepare to fail
524 */
Willy Tarreau12785782012-04-27 21:37:17 +0200525 if (!sample_casts[p->type][conv_expr->conv->in_type])
Willy Tarreau12e50112012-04-25 17:21:49 +0200526 return NULL;
527
Willy Tarreau12785782012-04-27 21:37:17 +0200528 if (sample_casts[p->type][conv_expr->conv->in_type] != c_none &&
529 !sample_casts[p->type][conv_expr->conv->in_type](p))
Emeric Brun107ca302010-01-04 16:16:05 +0100530 return NULL;
531
Willy Tarreau12e50112012-04-25 17:21:49 +0200532 /* OK cast succeeded */
533
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200534 /* force the output type after a cast */
Emeric Brun107ca302010-01-04 16:16:05 +0100535 p->type = conv_expr->conv->in_type;
Willy Tarreau342acb42012-04-23 22:03:39 +0200536 if (!conv_expr->conv->process(conv_expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100537 return NULL;
Emeric Brun107ca302010-01-04 16:16:05 +0100538 }
539 return p;
540}
541
Emeric Brun107ca302010-01-04 16:16:05 +0100542/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200543/* Sample format convert functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200544/* These functions set the data type on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100545/*****************************************************************/
546
Willy Tarreau12785782012-04-27 21:37:17 +0200547static int sample_conv_str2lower(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100548{
549 int i;
550
Willy Tarreau342acb42012-04-23 22:03:39 +0200551 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200552 return 0;
553
Willy Tarreau342acb42012-04-23 22:03:39 +0200554 for (i = 0; i < smp->data.str.len; i++) {
555 if ((smp->data.str.str[i] >= 'A') && (smp->data.str.str[i] <= 'Z'))
556 smp->data.str.str[i] += 'a' - 'A';
Emeric Brun107ca302010-01-04 16:16:05 +0100557 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200558 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100559 return 1;
560}
561
Willy Tarreau12785782012-04-27 21:37:17 +0200562static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100563{
564 int i;
565
Willy Tarreau342acb42012-04-23 22:03:39 +0200566 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200567 return 0;
568
Willy Tarreau342acb42012-04-23 22:03:39 +0200569 for (i = 0; i < smp->data.str.len; i++) {
570 if ((smp->data.str.str[i] >= 'a') && (smp->data.str.str[i] <= 'z'))
571 smp->data.str.str[i] += 'A' - 'a';
Emeric Brun107ca302010-01-04 16:16:05 +0100572 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200573 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100574 return 1;
575}
576
Willy Tarreauf9954102012-04-20 14:03:29 +0200577/* takes the netmask in arg_p */
Willy Tarreau12785782012-04-27 21:37:17 +0200578static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100579{
Willy Tarreau342acb42012-04-23 22:03:39 +0200580 smp->data.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200581 smp->type = SMP_T_IPV4;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100582 return 1;
583}
584
Emeric Brun107ca302010-01-04 16:16:05 +0100585/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreau12785782012-04-27 21:37:17 +0200586static struct sample_conv_kw_list sample_conv_kws = {{ },{
587 { "upper", sample_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
588 { "lower", sample_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
589 { "ipmask", sample_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200590 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100591}};
592
593__attribute__((constructor))
Willy Tarreau12785782012-04-27 21:37:17 +0200594static void __sample_init(void)
Emeric Brun107ca302010-01-04 16:16:05 +0100595{
Willy Tarreau12785782012-04-27 21:37:17 +0200596 /* register sample format convert keywords */
597 sample_register_convs(&sample_conv_kws);
Emeric Brun107ca302010-01-04 16:16:05 +0100598}