blob: f14b99b91530156dfe6e079e90a0c5d800c250df [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>
Emeric Brun107ca302010-01-04 16:16:05 +010016
Willy Tarreaucd3b0942012-04-27 21:52:18 +020017#include <common/standard.h>
18
Willy Tarreau9fcb9842012-04-20 14:45:49 +020019#include <proto/arg.h>
Emeric Brun485479d2010-09-23 18:02:19 +020020#include <proto/buffers.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020021#include <proto/sample.h>
Emeric Brun107ca302010-01-04 16:16:05 +010022
Willy Tarreau12785782012-04-27 21:37:17 +020023/* static sample used in sample_process() when <p> is NULL */
Willy Tarreaub4a88f02012-04-23 21:35:11 +020024static struct sample temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +010025
Willy Tarreau12785782012-04-27 21:37:17 +020026/* trash chunk used for sample conversions */
Emeric Brun107ca302010-01-04 16:16:05 +010027static struct chunk trash_chunk;
28
Willy Tarreau12785782012-04-27 21:37:17 +020029/* trash buffers used or sample conversions */
30static char sample_trash_buf1[BUFSIZE];
31static char sample_trash_buf2[BUFSIZE];
Emeric Brun107ca302010-01-04 16:16:05 +010032
Willy Tarreau12785782012-04-27 21:37:17 +020033/* sample_trash_buf point on used buffer*/
34static char *sample_trash_buf = sample_trash_buf1;
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*/
109static struct chunk *get_trash_chunk(void)
110{
Willy Tarreau12785782012-04-27 21:37:17 +0200111 if (sample_trash_buf == sample_trash_buf1)
112 sample_trash_buf = sample_trash_buf2;
Emeric Brun107ca302010-01-04 16:16:05 +0100113 else
Willy Tarreau12785782012-04-27 21:37:17 +0200114 sample_trash_buf = sample_trash_buf1;
Emeric Brun107ca302010-01-04 16:16:05 +0100115
Willy Tarreau12785782012-04-27 21:37:17 +0200116 chunk_init(&trash_chunk, sample_trash_buf, BUFSIZE);
Emeric Brun107ca302010-01-04 16:16:05 +0100117
118 return &trash_chunk;
119}
120
Emeric Brun107ca302010-01-04 16:16:05 +0100121/******************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200122/* Sample casts functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200123/* Note: these functions do *NOT* set the output type on the */
124/* sample, the caller is responsible for doing this on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100125/******************************************************************/
126
Willy Tarreau342acb42012-04-23 22:03:39 +0200127static int c_ip2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100128{
Willy Tarreau342acb42012-04-23 22:03:39 +0200129 smp->data.uint = ntohl(smp->data.ipv4.s_addr);
Emeric Brun107ca302010-01-04 16:16:05 +0100130 return 1;
131}
132
Willy Tarreau342acb42012-04-23 22:03:39 +0200133static int c_ip2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100134{
135 struct chunk *trash = get_trash_chunk();
136
Willy Tarreau342acb42012-04-23 22:03:39 +0200137 if (!inet_ntop(AF_INET, (void *)&smp->data.ipv4, trash->str, trash->size))
Emeric Brun107ca302010-01-04 16:16:05 +0100138 return 0;
139
140 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200141 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100142
143 return 1;
144}
145
Willy Tarreau342acb42012-04-23 22:03:39 +0200146static int c_ip2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100147{
Willy Tarreau342acb42012-04-23 22:03:39 +0200148 v4tov6(&smp->data.ipv6, &smp->data.ipv4);
David du Colombier4f92d322011-03-24 11:09:31 +0100149 return 1;
150}
151
Willy Tarreau342acb42012-04-23 22:03:39 +0200152static int c_ipv62str(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100153{
154 struct chunk *trash = get_trash_chunk();
155
Willy Tarreau342acb42012-04-23 22:03:39 +0200156 if (!inet_ntop(AF_INET6, (void *)&smp->data.ipv6, trash->str, trash->size))
David du Colombier4f92d322011-03-24 11:09:31 +0100157 return 0;
158
159 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200160 smp->data.str = *trash;
David du Colombier4f92d322011-03-24 11:09:31 +0100161 return 1;
162}
163
164/*
Willy Tarreau342acb42012-04-23 22:03:39 +0200165static int c_ipv62ip(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100166{
Willy Tarreau342acb42012-04-23 22:03:39 +0200167 return v6tov4(&smp->data.ipv4, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100168}
169*/
170
Willy Tarreau342acb42012-04-23 22:03:39 +0200171static int c_int2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100172{
Willy Tarreau342acb42012-04-23 22:03:39 +0200173 smp->data.ipv4.s_addr = htonl(smp->data.uint);
Emeric Brun107ca302010-01-04 16:16:05 +0100174 return 1;
175}
176
Willy Tarreau342acb42012-04-23 22:03:39 +0200177static int c_str2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100178{
Willy Tarreau342acb42012-04-23 22:03:39 +0200179 if (!buf2ip(smp->data.str.str, smp->data.str.len, &smp->data.ipv4))
Emeric Brun107ca302010-01-04 16:16:05 +0100180 return 0;
181 return 1;
182}
183
Willy Tarreau342acb42012-04-23 22:03:39 +0200184static int c_str2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100185{
Willy Tarreau342acb42012-04-23 22:03:39 +0200186 return inet_pton(AF_INET6, smp->data.str.str, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100187}
188
Willy Tarreau342acb42012-04-23 22:03:39 +0200189static int c_int2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100190{
191 struct chunk *trash = get_trash_chunk();
192 char *pos;
193
Willy Tarreau342acb42012-04-23 22:03:39 +0200194 pos = ultoa_r(smp->data.uint, trash->str, trash->size);
Emeric Brun107ca302010-01-04 16:16:05 +0100195
196 if (!pos)
197 return 0;
198
Emeric Brun485479d2010-09-23 18:02:19 +0200199 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100200 trash->str = pos;
201 trash->len = strlen(pos);
Willy Tarreau342acb42012-04-23 22:03:39 +0200202 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100203 return 1;
204}
205
Willy Tarreau342acb42012-04-23 22:03:39 +0200206static int c_datadup(struct sample *smp)
Emeric Brun485479d2010-09-23 18:02:19 +0200207{
208 struct chunk *trash = get_trash_chunk();
209
Willy Tarreau342acb42012-04-23 22:03:39 +0200210 trash->len = smp->data.str.len < trash->size ? smp->data.str.len : trash->size;
211 memcpy(trash->str, smp->data.str.str, trash->len);
212 smp->data.str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200213 return 1;
214}
215
216
Willy Tarreau342acb42012-04-23 22:03:39 +0200217static int c_none(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100218{
219 return 1;
220}
221
Willy Tarreau342acb42012-04-23 22:03:39 +0200222static int c_str2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100223{
224 int i;
225 uint32_t ret = 0;
226
Willy Tarreau342acb42012-04-23 22:03:39 +0200227 for (i = 0; i < smp->data.str.len; i++) {
228 uint32_t val = smp->data.str.str[i] - '0';
Emeric Brun107ca302010-01-04 16:16:05 +0100229
230 if (val > 9)
231 break;
232
233 ret = ret * 10 + val;
234 }
235
Willy Tarreau342acb42012-04-23 22:03:39 +0200236 smp->data.uint = ret;
Emeric Brun107ca302010-01-04 16:16:05 +0100237 return 1;
238}
239
240/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200241/* Sample casts matrix: */
242/* sample_casts[from type][to type] */
243/* NULL pointer used for impossible sample casts */
Emeric Brun107ca302010-01-04 16:16:05 +0100244/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100245
Willy Tarreau12785782012-04-27 21:37:17 +0200246typedef int (*sample_cast_fct)(struct sample *smp);
247static sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
Willy Tarreau422aa072012-04-20 20:49:27 +0200248/* to: BOOL UINT SINT IPV4 IPV6 STR BIN CSTR CBIN */
249/* from: BOOL */ { c_none, c_none, c_none, NULL, NULL, NULL, NULL, NULL, NULL },
250/* UINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
251/* SINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
252/* IPV4 */ { NULL, c_ip2int, c_ip2int, c_none, c_ip2ipv6, c_ip2str, NULL, c_ip2str, NULL },
253/* IPV6 */ { NULL, NULL, NULL, NULL, c_none, c_ipv62str, NULL, c_ipv62str, NULL },
254/* STR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_none, c_none, c_none, c_none },
255/* BIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_none, NULL, c_none },
256/* CSTR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_datadup, c_datadup, c_none, c_none },
257/* CBIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_datadup, NULL, c_none },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200258};
Emeric Brun107ca302010-01-04 16:16:05 +0100259
Emeric Brun107ca302010-01-04 16:16:05 +0100260/*
Willy Tarreau12785782012-04-27 21:37:17 +0200261 * Parse a sample expression configuration:
Emeric Brun107ca302010-01-04 16:16:05 +0100262 * fetch keyword followed by format conversion keywords.
Willy Tarreau12785782012-04-27 21:37:17 +0200263 * Returns a pointer on allocated sample expression structure.
Emeric Brun107ca302010-01-04 16:16:05 +0100264 */
Willy Tarreau12785782012-04-27 21:37:17 +0200265struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100266{
267 const char *endw;
268 const char *end;
Willy Tarreau12785782012-04-27 21:37:17 +0200269 struct sample_expr *expr;
270 struct sample_fetch *fetch;
271 struct sample_conv *conv;
Emeric Brun107ca302010-01-04 16:16:05 +0100272 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200273 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100274
Emeric Brun485479d2010-09-23 18:02:19 +0200275 snprintf(err, err_size, "memory error.");
276 if (!str[*idx]) {
277
278 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100279 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200280 }
Emeric Brun107ca302010-01-04 16:16:05 +0100281
282 end = str[*idx] + strlen(str[*idx]);
283 endw = strchr(str[*idx], '(');
284
285 if (!endw)
286 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200287 else if ((end-1)[0] != ')') {
288 p = my_strndup(str[*idx], endw - str[*idx]);
289 if (p) {
290 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
291 free(p);
292 }
Emeric Brun107ca302010-01-04 16:16:05 +0100293 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200294 }
Emeric Brun107ca302010-01-04 16:16:05 +0100295
Willy Tarreau12785782012-04-27 21:37:17 +0200296 fetch = find_sample_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200297 if (!fetch) {
298 p = my_strndup(str[*idx], endw - str[*idx]);
299 if (p) {
300 snprintf(err, err_size, "unknown fetch method '%s'.", p);
301 free(p);
302 }
Emeric Brun107ca302010-01-04 16:16:05 +0100303 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200304 }
Willy Tarreau422aa072012-04-20 20:49:27 +0200305 if (fetch->out_type >= SMP_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100306
Emeric Brun485479d2010-09-23 18:02:19 +0200307 p = my_strndup(str[*idx], endw - str[*idx]);
308 if (p) {
309 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
310 free(p);
311 }
Emeric Brun107ca302010-01-04 16:16:05 +0100312 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200313 }
Emeric Brun107ca302010-01-04 16:16:05 +0100314
315 prev_type = fetch->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200316 expr = calloc(1, sizeof(struct sample_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200317 if (!expr)
318 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100319
320 LIST_INIT(&(expr->conv_exprs));
321 expr->fetch = fetch;
322
323 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200324 char *err_msg = NULL;
325 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200326
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200327 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200328 p = my_strndup(str[*idx], endw - str[*idx]);
329 if (p) {
330 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
331 free(p);
332 }
333 goto out_error;
334 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200335
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200336 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 +0200337 p = my_strndup(str[*idx], endw - str[*idx]);
338 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200339 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 +0200340 free(p);
341 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200342 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200343 goto out_error;
344 }
345
346 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
347 p = my_strndup(str[*idx], endw - str[*idx]);
348 if (p) {
349 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
350 free(p);
351 }
352 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200353 goto out_error;
354 }
355 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200356 else if (fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200357 p = my_strndup(str[*idx], endw - str[*idx]);
358 if (p) {
359 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
360 free(p);
361 }
362 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100363 }
364
365 for (*idx += 1; *(str[*idx]); (*idx)++) {
Willy Tarreau12785782012-04-27 21:37:17 +0200366 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100367
368 end = str[*idx] + strlen(str[*idx]);
369 endw = strchr(str[*idx], '(');
370
371 if (!endw)
372 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200373 else if ((end-1)[0] != ')') {
374 p = my_strndup(str[*idx], endw - str[*idx]);
375 if (p) {
376 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
377 free(p);
378 }
Emeric Brun107ca302010-01-04 16:16:05 +0100379 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200380 }
Emeric Brun107ca302010-01-04 16:16:05 +0100381
Willy Tarreau12785782012-04-27 21:37:17 +0200382 conv = find_sample_conv(str[*idx], endw - str[*idx]);
Emeric Brun107ca302010-01-04 16:16:05 +0100383 if (!conv)
384 break;
385
Willy Tarreau422aa072012-04-20 20:49:27 +0200386 if (conv->in_type >= SMP_TYPES ||
387 conv->out_type >= SMP_TYPES) {
Emeric Brun485479d2010-09-23 18:02:19 +0200388 p = my_strndup(str[*idx], endw - str[*idx]);
389 if (p) {
390 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
391 free(p);
392 }
Emeric Brun107ca302010-01-04 16:16:05 +0100393 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200394 }
Emeric Brun107ca302010-01-04 16:16:05 +0100395
396 /* If impossible type conversion */
Willy Tarreau12785782012-04-27 21:37:17 +0200397 if (!sample_casts[prev_type][conv->in_type]) {
Emeric Brun485479d2010-09-23 18:02:19 +0200398 p = my_strndup(str[*idx], endw - str[*idx]);
399 if (p) {
400 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
401 free(p);
402 }
Emeric Brun107ca302010-01-04 16:16:05 +0100403 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200404 }
Emeric Brun107ca302010-01-04 16:16:05 +0100405
406 prev_type = conv->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200407 conv_expr = calloc(1, sizeof(struct sample_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200408 if (!conv_expr)
409 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100410
411 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
412 conv_expr->conv = conv;
413
414 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200415 char *err_msg = NULL;
416 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200417
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200418 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200419 p = my_strndup(str[*idx], endw - str[*idx]);
420
421 if (p) {
422 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
423 free(p);
424 }
425 goto out_error;
426 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100427
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200428 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 +0200429 p = my_strndup(str[*idx], endw - str[*idx]);
430 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200431 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 +0200432 free(p);
433 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200434 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200435 goto out_error;
436 }
437
438 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
439 p = my_strndup(str[*idx], endw - str[*idx]);
440 if (p) {
441 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
442 free(p);
443 }
444 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200445 goto out_error;
446 }
447 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200448 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200449 p = my_strndup(str[*idx], endw - str[*idx]);
450 if (p) {
451 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100452 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100453 }
Emeric Brun485479d2010-09-23 18:02:19 +0200454 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100455 }
Emeric Brun485479d2010-09-23 18:02:19 +0200456
Emeric Brun107ca302010-01-04 16:16:05 +0100457 }
Emeric Brun485479d2010-09-23 18:02:19 +0200458
Emeric Brun107ca302010-01-04 16:16:05 +0100459 return expr;
460
461out_error:
Willy Tarreau12785782012-04-27 21:37:17 +0200462 /* TODO: prune_sample_expr(expr); */
Emeric Brun107ca302010-01-04 16:16:05 +0100463 return NULL;
464}
465
466/*
Willy Tarreau12785782012-04-27 21:37:17 +0200467 * Process a fetch + format conversion of defined by the sample expression <expr>
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200468 * on request or response considering the <opt> parameter.
Willy Tarreau12785782012-04-27 21:37:17 +0200469 * Returns a pointer on a typed sample structure containing the result or NULL if
470 * sample is not found or when format conversion failed.
Emeric Brun107ca302010-01-04 16:16:05 +0100471 * If <p> is not null, function returns results in structure pointed by <p>.
Willy Tarreau12785782012-04-27 21:37:17 +0200472 * If <p> is null, functions returns a pointer on a static sample structure.
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200473 *
474 * Note: the fetch functions are required to properly set the return type. The
475 * conversion functions must do so too. However the cast functions do not need
476 * to since they're made to cast mutiple types according to what is required.
Emeric Brun107ca302010-01-04 16:16:05 +0100477 */
Willy Tarreau12785782012-04-27 21:37:17 +0200478struct sample *sample_process(struct proxy *px, struct session *l4, void *l7,
479 unsigned int opt,
480 struct sample_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100481{
Willy Tarreau12785782012-04-27 21:37:17 +0200482 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100483
484 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200485 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100486
Willy Tarreau342acb42012-04-23 22:03:39 +0200487 p->flags = 0;
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200488 if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100489 return NULL;
490
Willy Tarreau40aebd92012-04-26 11:05:50 +0200491 if (p->flags & SMP_F_MAY_CHANGE)
Willy Tarreau12785782012-04-27 21:37:17 +0200492 return NULL; /* we can only use stable samples */
Willy Tarreau40aebd92012-04-26 11:05:50 +0200493
Emeric Brun107ca302010-01-04 16:16:05 +0100494 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
Willy Tarreau12e50112012-04-25 17:21:49 +0200495 /* we want to ensure that p->type can be casted into
496 * conv_expr->conv->in_type. We have 3 possibilities :
497 * - NULL => not castable.
498 * - c_none => nothing to do (let's optimize it)
499 * - other => apply cast and prepare to fail
500 */
Willy Tarreau12785782012-04-27 21:37:17 +0200501 if (!sample_casts[p->type][conv_expr->conv->in_type])
Willy Tarreau12e50112012-04-25 17:21:49 +0200502 return NULL;
503
Willy Tarreau12785782012-04-27 21:37:17 +0200504 if (sample_casts[p->type][conv_expr->conv->in_type] != c_none &&
505 !sample_casts[p->type][conv_expr->conv->in_type](p))
Emeric Brun107ca302010-01-04 16:16:05 +0100506 return NULL;
507
Willy Tarreau12e50112012-04-25 17:21:49 +0200508 /* OK cast succeeded */
509
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200510 /* force the output type after a cast */
Emeric Brun107ca302010-01-04 16:16:05 +0100511 p->type = conv_expr->conv->in_type;
Willy Tarreau342acb42012-04-23 22:03:39 +0200512 if (!conv_expr->conv->process(conv_expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100513 return NULL;
Emeric Brun107ca302010-01-04 16:16:05 +0100514 }
515 return p;
516}
517
Emeric Brun107ca302010-01-04 16:16:05 +0100518/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200519/* Sample format convert functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200520/* These functions set the data type on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100521/*****************************************************************/
522
Willy Tarreau12785782012-04-27 21:37:17 +0200523static int sample_conv_str2lower(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100524{
525 int i;
526
Willy Tarreau342acb42012-04-23 22:03:39 +0200527 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200528 return 0;
529
Willy Tarreau342acb42012-04-23 22:03:39 +0200530 for (i = 0; i < smp->data.str.len; i++) {
531 if ((smp->data.str.str[i] >= 'A') && (smp->data.str.str[i] <= 'Z'))
532 smp->data.str.str[i] += 'a' - 'A';
Emeric Brun107ca302010-01-04 16:16:05 +0100533 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200534 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100535 return 1;
536}
537
Willy Tarreau12785782012-04-27 21:37:17 +0200538static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100539{
540 int i;
541
Willy Tarreau342acb42012-04-23 22:03:39 +0200542 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200543 return 0;
544
Willy Tarreau342acb42012-04-23 22:03:39 +0200545 for (i = 0; i < smp->data.str.len; i++) {
546 if ((smp->data.str.str[i] >= 'a') && (smp->data.str.str[i] <= 'z'))
547 smp->data.str.str[i] += 'A' - 'a';
Emeric Brun107ca302010-01-04 16:16:05 +0100548 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200549 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100550 return 1;
551}
552
Willy Tarreauf9954102012-04-20 14:03:29 +0200553/* takes the netmask in arg_p */
Willy Tarreau12785782012-04-27 21:37:17 +0200554static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100555{
Willy Tarreau342acb42012-04-23 22:03:39 +0200556 smp->data.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200557 smp->type = SMP_T_IPV4;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100558 return 1;
559}
560
Emeric Brun107ca302010-01-04 16:16:05 +0100561/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreau12785782012-04-27 21:37:17 +0200562static struct sample_conv_kw_list sample_conv_kws = {{ },{
563 { "upper", sample_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
564 { "lower", sample_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
565 { "ipmask", sample_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200566 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100567}};
568
569__attribute__((constructor))
Willy Tarreau12785782012-04-27 21:37:17 +0200570static void __sample_init(void)
Emeric Brun107ca302010-01-04 16:16:05 +0100571{
Willy Tarreau12785782012-04-27 21:37:17 +0200572 /* register sample format convert keywords */
573 sample_register_convs(&sample_conv_kws);
Emeric Brun107ca302010-01-04 16:16:05 +0100574}