blob: b3898e0a82d065b461fed7dc54d51c0f5cd04a36 [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/* list head of all known sample fetch keywords */
30static struct sample_fetch_kw_list sample_fetches = {
31 .list = LIST_HEAD_INIT(sample_fetches.list)
Emeric Brun107ca302010-01-04 16:16:05 +010032};
33
Willy Tarreau12785782012-04-27 21:37:17 +020034/* list head of all known sample format conversion keywords */
35static struct sample_conv_kw_list sample_convs = {
36 .list = LIST_HEAD_INIT(sample_convs.list)
Emeric Brun107ca302010-01-04 16:16:05 +010037};
38
39/*
Willy Tarreau12785782012-04-27 21:37:17 +020040 * Registers the sample fetch keyword list <kwl> as a list of valid keywords for next
Emeric Brun107ca302010-01-04 16:16:05 +010041 * parsing sessions.
42 */
Willy Tarreau12785782012-04-27 21:37:17 +020043void sample_register_fetches(struct sample_fetch_kw_list *pfkl)
Emeric Brun107ca302010-01-04 16:16:05 +010044{
Willy Tarreau12785782012-04-27 21:37:17 +020045 LIST_ADDQ(&sample_fetches.list, &pfkl->list);
Emeric Brun107ca302010-01-04 16:16:05 +010046}
47
48/*
Willy Tarreau12785782012-04-27 21:37:17 +020049 * Registers the sample format coverstion keyword list <pckl> as a list of valid keywords for next
Emeric Brun107ca302010-01-04 16:16:05 +010050 * parsing sessions.
51 */
Willy Tarreau12785782012-04-27 21:37:17 +020052void sample_register_convs(struct sample_conv_kw_list *pckl)
Emeric Brun107ca302010-01-04 16:16:05 +010053{
Willy Tarreau12785782012-04-27 21:37:17 +020054 LIST_ADDQ(&sample_convs.list, &pckl->list);
Emeric Brun107ca302010-01-04 16:16:05 +010055}
56
57/*
Willy Tarreau12785782012-04-27 21:37:17 +020058 * Returns the pointer on sample fetch keyword structure identified by
Emeric Brun107ca302010-01-04 16:16:05 +010059 * string of <len> in buffer <kw>.
60 *
61 */
Willy Tarreau12785782012-04-27 21:37:17 +020062struct sample_fetch *find_sample_fetch(const char *kw, int len)
Emeric Brun107ca302010-01-04 16:16:05 +010063{
64 int index;
Willy Tarreau12785782012-04-27 21:37:17 +020065 struct sample_fetch_kw_list *kwl;
Emeric Brun107ca302010-01-04 16:16:05 +010066
Willy Tarreau12785782012-04-27 21:37:17 +020067 list_for_each_entry(kwl, &sample_fetches.list, list) {
Emeric Brun107ca302010-01-04 16:16:05 +010068 for (index = 0; kwl->kw[index].kw != NULL; index++) {
69 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
70 kwl->kw[index].kw[len] == '\0')
71 return &kwl->kw[index];
72 }
73 }
74 return NULL;
75}
76
77/*
Willy Tarreau12785782012-04-27 21:37:17 +020078 * Returns the pointer on sample format conversion keyword structure identified by
Emeric Brun107ca302010-01-04 16:16:05 +010079 * string of <len> in buffer <kw>.
80 *
81 */
Willy Tarreau12785782012-04-27 21:37:17 +020082struct sample_conv *find_sample_conv(const char *kw, int len)
Emeric Brun107ca302010-01-04 16:16:05 +010083{
84 int index;
Willy Tarreau12785782012-04-27 21:37:17 +020085 struct sample_conv_kw_list *kwl;
Emeric Brun107ca302010-01-04 16:16:05 +010086
Willy Tarreau12785782012-04-27 21:37:17 +020087 list_for_each_entry(kwl, &sample_convs.list, list) {
Emeric Brun107ca302010-01-04 16:16:05 +010088 for (index = 0; kwl->kw[index].kw != NULL; index++) {
89 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
90 kwl->kw[index].kw[len] == '\0')
91 return &kwl->kw[index];
92 }
93 }
94 return NULL;
95}
96
Emeric Brun107ca302010-01-04 16:16:05 +010097/******************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +020098/* Sample casts functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +020099/* Note: these functions do *NOT* set the output type on the */
100/* sample, the caller is responsible for doing this on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100101/******************************************************************/
102
Willy Tarreau342acb42012-04-23 22:03:39 +0200103static int c_ip2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100104{
Willy Tarreau342acb42012-04-23 22:03:39 +0200105 smp->data.uint = ntohl(smp->data.ipv4.s_addr);
Emeric Brun107ca302010-01-04 16:16:05 +0100106 return 1;
107}
108
Willy Tarreau342acb42012-04-23 22:03:39 +0200109static int c_ip2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100110{
Willy Tarreau47ca5452012-12-23 20:22:19 +0100111 struct chunk *trash = get_trash_chunk();
Emeric Brun107ca302010-01-04 16:16:05 +0100112
Willy Tarreau342acb42012-04-23 22:03:39 +0200113 if (!inet_ntop(AF_INET, (void *)&smp->data.ipv4, trash->str, trash->size))
Emeric Brun107ca302010-01-04 16:16:05 +0100114 return 0;
115
116 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200117 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100118
119 return 1;
120}
121
Willy Tarreau342acb42012-04-23 22:03:39 +0200122static int c_ip2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100123{
Willy Tarreau342acb42012-04-23 22:03:39 +0200124 v4tov6(&smp->data.ipv6, &smp->data.ipv4);
David du Colombier4f92d322011-03-24 11:09:31 +0100125 return 1;
126}
127
Willy Tarreau342acb42012-04-23 22:03:39 +0200128static int c_ipv62str(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100129{
Willy Tarreau47ca5452012-12-23 20:22:19 +0100130 struct chunk *trash = get_trash_chunk();
David du Colombier4f92d322011-03-24 11:09:31 +0100131
Willy Tarreau342acb42012-04-23 22:03:39 +0200132 if (!inet_ntop(AF_INET6, (void *)&smp->data.ipv6, trash->str, trash->size))
David du Colombier4f92d322011-03-24 11:09:31 +0100133 return 0;
134
135 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200136 smp->data.str = *trash;
David du Colombier4f92d322011-03-24 11:09:31 +0100137 return 1;
138}
139
140/*
Willy Tarreau342acb42012-04-23 22:03:39 +0200141static int c_ipv62ip(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100142{
Willy Tarreau342acb42012-04-23 22:03:39 +0200143 return v6tov4(&smp->data.ipv4, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100144}
145*/
146
Willy Tarreau342acb42012-04-23 22:03:39 +0200147static int c_int2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100148{
Willy Tarreau342acb42012-04-23 22:03:39 +0200149 smp->data.ipv4.s_addr = htonl(smp->data.uint);
Emeric Brun107ca302010-01-04 16:16:05 +0100150 return 1;
151}
152
Willy Tarreau342acb42012-04-23 22:03:39 +0200153static int c_str2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100154{
Willy Tarreau342acb42012-04-23 22:03:39 +0200155 if (!buf2ip(smp->data.str.str, smp->data.str.len, &smp->data.ipv4))
Emeric Brun107ca302010-01-04 16:16:05 +0100156 return 0;
157 return 1;
158}
159
Willy Tarreau342acb42012-04-23 22:03:39 +0200160static int c_str2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100161{
Willy Tarreau342acb42012-04-23 22:03:39 +0200162 return inet_pton(AF_INET6, smp->data.str.str, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100163}
164
Emeric Brun8ac33d92012-10-17 13:36:06 +0200165static int c_bin2str(struct sample *smp)
166{
Willy Tarreau47ca5452012-12-23 20:22:19 +0100167 struct chunk *trash = get_trash_chunk();
Emeric Brun8ac33d92012-10-17 13:36:06 +0200168 unsigned char c;
169 int ptr = 0;
170
171 trash->len = 0;
172 while (ptr < smp->data.str.len && trash->len <= trash->size - 2) {
173 c = smp->data.str.str[ptr++];
174 trash->str[trash->len++] = hextab[(c >> 4) & 0xF];
175 trash->str[trash->len++] = hextab[c & 0xF];
176 }
177 smp->data.str = *trash;
178 return 1;
179}
180
Willy Tarreau342acb42012-04-23 22:03:39 +0200181static int c_int2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100182{
Willy Tarreau47ca5452012-12-23 20:22:19 +0100183 struct chunk *trash = get_trash_chunk();
Emeric Brun107ca302010-01-04 16:16:05 +0100184 char *pos;
185
Willy Tarreau342acb42012-04-23 22:03:39 +0200186 pos = ultoa_r(smp->data.uint, trash->str, trash->size);
Emeric Brun107ca302010-01-04 16:16:05 +0100187
188 if (!pos)
189 return 0;
190
Emeric Brun485479d2010-09-23 18:02:19 +0200191 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100192 trash->str = pos;
193 trash->len = strlen(pos);
Willy Tarreau342acb42012-04-23 22:03:39 +0200194 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100195 return 1;
196}
197
Willy Tarreau342acb42012-04-23 22:03:39 +0200198static int c_datadup(struct sample *smp)
Emeric Brun485479d2010-09-23 18:02:19 +0200199{
Willy Tarreau47ca5452012-12-23 20:22:19 +0100200 struct chunk *trash = get_trash_chunk();
Emeric Brun485479d2010-09-23 18:02:19 +0200201
Willy Tarreau342acb42012-04-23 22:03:39 +0200202 trash->len = smp->data.str.len < trash->size ? smp->data.str.len : trash->size;
203 memcpy(trash->str, smp->data.str.str, trash->len);
204 smp->data.str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200205 return 1;
206}
207
208
Willy Tarreau342acb42012-04-23 22:03:39 +0200209static int c_none(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100210{
211 return 1;
212}
213
Willy Tarreau342acb42012-04-23 22:03:39 +0200214static int c_str2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100215{
216 int i;
217 uint32_t ret = 0;
218
Willy Tarreau342acb42012-04-23 22:03:39 +0200219 for (i = 0; i < smp->data.str.len; i++) {
220 uint32_t val = smp->data.str.str[i] - '0';
Emeric Brun107ca302010-01-04 16:16:05 +0100221
222 if (val > 9)
223 break;
224
225 ret = ret * 10 + val;
226 }
227
Willy Tarreau342acb42012-04-23 22:03:39 +0200228 smp->data.uint = ret;
Emeric Brun107ca302010-01-04 16:16:05 +0100229 return 1;
230}
231
232/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200233/* Sample casts matrix: */
234/* sample_casts[from type][to type] */
235/* NULL pointer used for impossible sample casts */
Emeric Brun107ca302010-01-04 16:16:05 +0100236/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100237
Willy Tarreau12785782012-04-27 21:37:17 +0200238typedef int (*sample_cast_fct)(struct sample *smp);
239static sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
Willy Tarreau422aa072012-04-20 20:49:27 +0200240/* to: BOOL UINT SINT IPV4 IPV6 STR BIN CSTR CBIN */
Willy Tarreaud167e6d2012-12-21 17:38:05 +0100241/* from: BOOL */ { c_none, c_none, c_none, NULL, NULL, c_int2str, NULL, c_int2str, NULL },
Willy Tarreau422aa072012-04-20 20:49:27 +0200242/* UINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
243/* SINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
244/* IPV4 */ { NULL, c_ip2int, c_ip2int, c_none, c_ip2ipv6, c_ip2str, NULL, c_ip2str, NULL },
245/* IPV6 */ { NULL, NULL, NULL, NULL, c_none, c_ipv62str, NULL, c_ipv62str, NULL },
246/* 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 +0200247/* BIN */ { NULL, NULL, NULL, NULL, NULL, c_bin2str, c_none, c_bin2str, c_none },
Willy Tarreau422aa072012-04-20 20:49:27 +0200248/* 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 +0200249/* CBIN */ { NULL, NULL, NULL, NULL, NULL, c_bin2str, c_datadup, c_bin2str, c_none },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200250};
Emeric Brun107ca302010-01-04 16:16:05 +0100251
Emeric Brun107ca302010-01-04 16:16:05 +0100252/*
Willy Tarreau12785782012-04-27 21:37:17 +0200253 * Parse a sample expression configuration:
Emeric Brun107ca302010-01-04 16:16:05 +0100254 * fetch keyword followed by format conversion keywords.
Willy Tarreau12785782012-04-27 21:37:17 +0200255 * Returns a pointer on allocated sample expression structure.
Emeric Brun107ca302010-01-04 16:16:05 +0100256 */
Willy Tarreau12785782012-04-27 21:37:17 +0200257struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100258{
259 const char *endw;
260 const char *end;
Willy Tarreau12785782012-04-27 21:37:17 +0200261 struct sample_expr *expr;
262 struct sample_fetch *fetch;
263 struct sample_conv *conv;
Emeric Brun107ca302010-01-04 16:16:05 +0100264 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200265 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100266
Emeric Brun485479d2010-09-23 18:02:19 +0200267 snprintf(err, err_size, "memory error.");
268 if (!str[*idx]) {
269
270 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100271 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200272 }
Emeric Brun107ca302010-01-04 16:16:05 +0100273
274 end = str[*idx] + strlen(str[*idx]);
275 endw = strchr(str[*idx], '(');
276
277 if (!endw)
278 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200279 else if ((end-1)[0] != ')') {
280 p = my_strndup(str[*idx], endw - str[*idx]);
281 if (p) {
282 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
283 free(p);
284 }
Emeric Brun107ca302010-01-04 16:16:05 +0100285 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200286 }
Emeric Brun107ca302010-01-04 16:16:05 +0100287
Willy Tarreau12785782012-04-27 21:37:17 +0200288 fetch = find_sample_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200289 if (!fetch) {
290 p = my_strndup(str[*idx], endw - str[*idx]);
291 if (p) {
292 snprintf(err, err_size, "unknown fetch method '%s'.", p);
293 free(p);
294 }
Emeric Brun107ca302010-01-04 16:16:05 +0100295 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200296 }
Willy Tarreau422aa072012-04-20 20:49:27 +0200297 if (fetch->out_type >= SMP_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100298
Emeric Brun485479d2010-09-23 18:02:19 +0200299 p = my_strndup(str[*idx], endw - str[*idx]);
300 if (p) {
301 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
302 free(p);
303 }
Emeric Brun107ca302010-01-04 16:16:05 +0100304 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200305 }
Emeric Brun107ca302010-01-04 16:16:05 +0100306
307 prev_type = fetch->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200308 expr = calloc(1, sizeof(struct sample_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200309 if (!expr)
310 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100311
312 LIST_INIT(&(expr->conv_exprs));
313 expr->fetch = fetch;
Willy Tarreau2e845be2012-10-19 19:49:09 +0200314 expr->arg_p = empty_arg_list;
Emeric Brun107ca302010-01-04 16:16:05 +0100315
316 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200317 char *err_msg = NULL;
318 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200319
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200320 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200321 p = my_strndup(str[*idx], endw - str[*idx]);
322 if (p) {
323 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
324 free(p);
325 }
326 goto out_error;
327 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200328
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200329 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 +0200330 p = my_strndup(str[*idx], endw - str[*idx]);
331 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200332 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 +0200333 free(p);
334 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200335 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200336 goto out_error;
337 }
338
Willy Tarreau2e845be2012-10-19 19:49:09 +0200339 if (!expr->arg_p)
340 expr->arg_p = empty_arg_list;
341
Willy Tarreau21d68a62012-04-20 15:52:36 +0200342 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
343 p = my_strndup(str[*idx], endw - str[*idx]);
344 if (p) {
345 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
346 free(p);
347 }
348 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200349 goto out_error;
350 }
351 }
Willy Tarreauf22a5082012-10-19 16:47:23 +0200352 else if (ARGM(fetch->arg_mask)) {
Emeric Brun485479d2010-09-23 18:02:19 +0200353 p = my_strndup(str[*idx], endw - str[*idx]);
354 if (p) {
355 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
356 free(p);
357 }
358 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100359 }
360
361 for (*idx += 1; *(str[*idx]); (*idx)++) {
Willy Tarreau12785782012-04-27 21:37:17 +0200362 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100363
364 end = str[*idx] + strlen(str[*idx]);
365 endw = strchr(str[*idx], '(');
366
367 if (!endw)
368 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200369 else if ((end-1)[0] != ')') {
370 p = my_strndup(str[*idx], endw - str[*idx]);
371 if (p) {
372 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
373 free(p);
374 }
Emeric Brun107ca302010-01-04 16:16:05 +0100375 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200376 }
Emeric Brun107ca302010-01-04 16:16:05 +0100377
Willy Tarreau12785782012-04-27 21:37:17 +0200378 conv = find_sample_conv(str[*idx], endw - str[*idx]);
Emeric Brun107ca302010-01-04 16:16:05 +0100379 if (!conv)
380 break;
381
Willy Tarreau422aa072012-04-20 20:49:27 +0200382 if (conv->in_type >= SMP_TYPES ||
383 conv->out_type >= SMP_TYPES) {
Emeric Brun485479d2010-09-23 18:02:19 +0200384 p = my_strndup(str[*idx], endw - str[*idx]);
385 if (p) {
386 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
387 free(p);
388 }
Emeric Brun107ca302010-01-04 16:16:05 +0100389 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200390 }
Emeric Brun107ca302010-01-04 16:16:05 +0100391
392 /* If impossible type conversion */
Willy Tarreau12785782012-04-27 21:37:17 +0200393 if (!sample_casts[prev_type][conv->in_type]) {
Emeric Brun485479d2010-09-23 18:02:19 +0200394 p = my_strndup(str[*idx], endw - str[*idx]);
395 if (p) {
396 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
397 free(p);
398 }
Emeric Brun107ca302010-01-04 16:16:05 +0100399 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200400 }
Emeric Brun107ca302010-01-04 16:16:05 +0100401
402 prev_type = conv->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200403 conv_expr = calloc(1, sizeof(struct sample_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200404 if (!conv_expr)
405 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100406
407 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
408 conv_expr->conv = conv;
409
410 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200411 char *err_msg = NULL;
412 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200413
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200414 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200415 p = my_strndup(str[*idx], endw - str[*idx]);
416
417 if (p) {
418 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
419 free(p);
420 }
421 goto out_error;
422 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100423
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200424 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 +0200425 p = my_strndup(str[*idx], endw - str[*idx]);
426 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200427 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 +0200428 free(p);
429 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200430 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200431 goto out_error;
432 }
433
Willy Tarreau2e845be2012-10-19 19:49:09 +0200434 if (!conv_expr->arg_p)
435 conv_expr->arg_p = empty_arg_list;
436
Willy Tarreau21d68a62012-04-20 15:52:36 +0200437 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
438 p = my_strndup(str[*idx], endw - str[*idx]);
439 if (p) {
440 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
441 free(p);
442 }
443 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200444 goto out_error;
445 }
446 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200447 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200448 p = my_strndup(str[*idx], endw - str[*idx]);
449 if (p) {
450 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100451 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100452 }
Emeric Brun485479d2010-09-23 18:02:19 +0200453 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100454 }
Emeric Brun485479d2010-09-23 18:02:19 +0200455
Emeric Brun107ca302010-01-04 16:16:05 +0100456 }
Emeric Brun485479d2010-09-23 18:02:19 +0200457
Emeric Brun107ca302010-01-04 16:16:05 +0100458 return expr;
459
460out_error:
Willy Tarreau12785782012-04-27 21:37:17 +0200461 /* TODO: prune_sample_expr(expr); */
Emeric Brun107ca302010-01-04 16:16:05 +0100462 return NULL;
463}
464
465/*
Willy Tarreau12785782012-04-27 21:37:17 +0200466 * Process a fetch + format conversion of defined by the sample expression <expr>
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200467 * on request or response considering the <opt> parameter.
Willy Tarreau12785782012-04-27 21:37:17 +0200468 * Returns a pointer on a typed sample structure containing the result or NULL if
469 * sample is not found or when format conversion failed.
Emeric Brun107ca302010-01-04 16:16:05 +0100470 * If <p> is not null, function returns results in structure pointed by <p>.
Willy Tarreau12785782012-04-27 21:37:17 +0200471 * If <p> is null, functions returns a pointer on a static sample structure.
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200472 *
473 * Note: the fetch functions are required to properly set the return type. The
474 * conversion functions must do so too. However the cast functions do not need
475 * to since they're made to cast mutiple types according to what is required.
Emeric Brun107ca302010-01-04 16:16:05 +0100476 */
Willy Tarreau12785782012-04-27 21:37:17 +0200477struct sample *sample_process(struct proxy *px, struct session *l4, void *l7,
478 unsigned int opt,
479 struct sample_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100480{
Willy Tarreau12785782012-04-27 21:37:17 +0200481 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100482
483 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200484 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100485
Willy Tarreau342acb42012-04-23 22:03:39 +0200486 p->flags = 0;
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200487 if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100488 return NULL;
489
Willy Tarreau40aebd92012-04-26 11:05:50 +0200490 if (p->flags & SMP_F_MAY_CHANGE)
Willy Tarreau12785782012-04-27 21:37:17 +0200491 return NULL; /* we can only use stable samples */
Willy Tarreau40aebd92012-04-26 11:05:50 +0200492
Emeric Brun107ca302010-01-04 16:16:05 +0100493 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
Willy Tarreau12e50112012-04-25 17:21:49 +0200494 /* we want to ensure that p->type can be casted into
495 * conv_expr->conv->in_type. We have 3 possibilities :
496 * - NULL => not castable.
497 * - c_none => nothing to do (let's optimize it)
498 * - other => apply cast and prepare to fail
499 */
Willy Tarreau12785782012-04-27 21:37:17 +0200500 if (!sample_casts[p->type][conv_expr->conv->in_type])
Willy Tarreau12e50112012-04-25 17:21:49 +0200501 return NULL;
502
Willy Tarreau12785782012-04-27 21:37:17 +0200503 if (sample_casts[p->type][conv_expr->conv->in_type] != c_none &&
504 !sample_casts[p->type][conv_expr->conv->in_type](p))
Emeric Brun107ca302010-01-04 16:16:05 +0100505 return NULL;
506
Willy Tarreau12e50112012-04-25 17:21:49 +0200507 /* OK cast succeeded */
508
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200509 /* force the output type after a cast */
Emeric Brun107ca302010-01-04 16:16:05 +0100510 p->type = conv_expr->conv->in_type;
Willy Tarreau342acb42012-04-23 22:03:39 +0200511 if (!conv_expr->conv->process(conv_expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100512 return NULL;
Emeric Brun107ca302010-01-04 16:16:05 +0100513 }
514 return p;
515}
516
Willy Tarreaue7ad4bb2012-12-21 00:02:32 +0100517/*
518 * Process a fetch + format conversion as defined by the sample expression <expr>
519 * on request or response considering the <opt> parameter. The output is always of
520 * type string. Returns either NULL if no sample could be extracted, or a pointer
521 * to the converted result stored in static temp_smp in format string.
522 */
523struct sample *sample_fetch_string(struct proxy *px, struct session *l4, void *l7,
524 unsigned int opt, struct sample_expr *expr)
525{
526 struct sample *smp;
527
528 smp = sample_process(px, l4, l7, opt, expr, NULL);
529 if (!smp)
530 return NULL;
531
532 if (!sample_casts[smp->type][SMP_T_CSTR])
533 return NULL;
534
535 if (!sample_casts[smp->type][SMP_T_CSTR](smp))
536 return NULL;
537
538 smp->type = SMP_T_CSTR;
539 return smp;
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}