blob: 3703a44b46cc8285d6724665977738fda9db3384 [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 Tarreauc7e42382012-08-24 19:22:53 +020018#include <common/chunk.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020019#include <common/standard.h>
20
Willy Tarreau9fcb9842012-04-20 14:45:49 +020021#include <proto/arg.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020022#include <proto/sample.h>
Emeric Brun107ca302010-01-04 16:16:05 +010023
Willy Tarreau12785782012-04-27 21:37:17 +020024/* static sample used in sample_process() when <p> is NULL */
Willy Tarreaub4a88f02012-04-23 21:35:11 +020025static struct sample temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +010026
Willy Tarreau12785782012-04-27 21:37:17 +020027/* trash chunk used for sample conversions */
Emeric Brun107ca302010-01-04 16:16:05 +010028static struct chunk trash_chunk;
29
Willy Tarreau12785782012-04-27 21:37:17 +020030/* trash buffers used or sample conversions */
31static char sample_trash_buf1[BUFSIZE];
32static char sample_trash_buf2[BUFSIZE];
Emeric Brun107ca302010-01-04 16:16:05 +010033
Willy Tarreau12785782012-04-27 21:37:17 +020034/* sample_trash_buf point on used buffer*/
35static char *sample_trash_buf = sample_trash_buf1;
Emeric Brun107ca302010-01-04 16:16:05 +010036
Willy Tarreau12785782012-04-27 21:37:17 +020037/* list head of all known sample fetch keywords */
38static struct sample_fetch_kw_list sample_fetches = {
39 .list = LIST_HEAD_INIT(sample_fetches.list)
Emeric Brun107ca302010-01-04 16:16:05 +010040};
41
Willy Tarreau12785782012-04-27 21:37:17 +020042/* list head of all known sample format conversion keywords */
43static struct sample_conv_kw_list sample_convs = {
44 .list = LIST_HEAD_INIT(sample_convs.list)
Emeric Brun107ca302010-01-04 16:16:05 +010045};
46
47/*
Willy Tarreau12785782012-04-27 21:37:17 +020048 * Registers the sample fetch keyword list <kwl> as a list of valid keywords for next
Emeric Brun107ca302010-01-04 16:16:05 +010049 * parsing sessions.
50 */
Willy Tarreau12785782012-04-27 21:37:17 +020051void sample_register_fetches(struct sample_fetch_kw_list *pfkl)
Emeric Brun107ca302010-01-04 16:16:05 +010052{
Willy Tarreau12785782012-04-27 21:37:17 +020053 LIST_ADDQ(&sample_fetches.list, &pfkl->list);
Emeric Brun107ca302010-01-04 16:16:05 +010054}
55
56/*
Willy Tarreau12785782012-04-27 21:37:17 +020057 * Registers the sample format coverstion keyword list <pckl> as a list of valid keywords for next
Emeric Brun107ca302010-01-04 16:16:05 +010058 * parsing sessions.
59 */
Willy Tarreau12785782012-04-27 21:37:17 +020060void sample_register_convs(struct sample_conv_kw_list *pckl)
Emeric Brun107ca302010-01-04 16:16:05 +010061{
Willy Tarreau12785782012-04-27 21:37:17 +020062 LIST_ADDQ(&sample_convs.list, &pckl->list);
Emeric Brun107ca302010-01-04 16:16:05 +010063}
64
65/*
Willy Tarreau12785782012-04-27 21:37:17 +020066 * Returns the pointer on sample fetch keyword structure identified by
Emeric Brun107ca302010-01-04 16:16:05 +010067 * string of <len> in buffer <kw>.
68 *
69 */
Willy Tarreau12785782012-04-27 21:37:17 +020070struct sample_fetch *find_sample_fetch(const char *kw, int len)
Emeric Brun107ca302010-01-04 16:16:05 +010071{
72 int index;
Willy Tarreau12785782012-04-27 21:37:17 +020073 struct sample_fetch_kw_list *kwl;
Emeric Brun107ca302010-01-04 16:16:05 +010074
Willy Tarreau12785782012-04-27 21:37:17 +020075 list_for_each_entry(kwl, &sample_fetches.list, list) {
Emeric Brun107ca302010-01-04 16:16:05 +010076 for (index = 0; kwl->kw[index].kw != NULL; index++) {
77 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
78 kwl->kw[index].kw[len] == '\0')
79 return &kwl->kw[index];
80 }
81 }
82 return NULL;
83}
84
85/*
Willy Tarreau12785782012-04-27 21:37:17 +020086 * Returns the pointer on sample format conversion keyword structure identified by
Emeric Brun107ca302010-01-04 16:16:05 +010087 * string of <len> in buffer <kw>.
88 *
89 */
Willy Tarreau12785782012-04-27 21:37:17 +020090struct sample_conv *find_sample_conv(const char *kw, int len)
Emeric Brun107ca302010-01-04 16:16:05 +010091{
92 int index;
Willy Tarreau12785782012-04-27 21:37:17 +020093 struct sample_conv_kw_list *kwl;
Emeric Brun107ca302010-01-04 16:16:05 +010094
Willy Tarreau12785782012-04-27 21:37:17 +020095 list_for_each_entry(kwl, &sample_convs.list, list) {
Emeric Brun107ca302010-01-04 16:16:05 +010096 for (index = 0; kwl->kw[index].kw != NULL; index++) {
97 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
98 kwl->kw[index].kw[len] == '\0')
99 return &kwl->kw[index];
100 }
101 }
102 return NULL;
103}
104
105
106/*
Willy Tarreau12785782012-04-27 21:37:17 +0200107* Returns a static trash struct chunk to use in sample casts or format conversions
Emeric Brun107ca302010-01-04 16:16:05 +0100108* Swiths the 2 available trash buffers to protect data during convert
109*/
110static struct chunk *get_trash_chunk(void)
111{
Willy Tarreau12785782012-04-27 21:37:17 +0200112 if (sample_trash_buf == sample_trash_buf1)
113 sample_trash_buf = sample_trash_buf2;
Emeric Brun107ca302010-01-04 16:16:05 +0100114 else
Willy Tarreau12785782012-04-27 21:37:17 +0200115 sample_trash_buf = sample_trash_buf1;
Emeric Brun107ca302010-01-04 16:16:05 +0100116
Willy Tarreau12785782012-04-27 21:37:17 +0200117 chunk_init(&trash_chunk, sample_trash_buf, 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{
136 struct chunk *trash = get_trash_chunk();
137
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{
155 struct chunk *trash = get_trash_chunk();
156
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
Willy Tarreau342acb42012-04-23 22:03:39 +0200190static int c_int2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100191{
192 struct chunk *trash = get_trash_chunk();
193 char *pos;
194
Willy Tarreau342acb42012-04-23 22:03:39 +0200195 pos = ultoa_r(smp->data.uint, trash->str, trash->size);
Emeric Brun107ca302010-01-04 16:16:05 +0100196
197 if (!pos)
198 return 0;
199
Emeric Brun485479d2010-09-23 18:02:19 +0200200 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100201 trash->str = pos;
202 trash->len = strlen(pos);
Willy Tarreau342acb42012-04-23 22:03:39 +0200203 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100204 return 1;
205}
206
Willy Tarreau342acb42012-04-23 22:03:39 +0200207static int c_datadup(struct sample *smp)
Emeric Brun485479d2010-09-23 18:02:19 +0200208{
209 struct chunk *trash = get_trash_chunk();
210
Willy Tarreau342acb42012-04-23 22:03:39 +0200211 trash->len = smp->data.str.len < trash->size ? smp->data.str.len : trash->size;
212 memcpy(trash->str, smp->data.str.str, trash->len);
213 smp->data.str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200214 return 1;
215}
216
217
Willy Tarreau342acb42012-04-23 22:03:39 +0200218static int c_none(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100219{
220 return 1;
221}
222
Willy Tarreau342acb42012-04-23 22:03:39 +0200223static int c_str2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100224{
225 int i;
226 uint32_t ret = 0;
227
Willy Tarreau342acb42012-04-23 22:03:39 +0200228 for (i = 0; i < smp->data.str.len; i++) {
229 uint32_t val = smp->data.str.str[i] - '0';
Emeric Brun107ca302010-01-04 16:16:05 +0100230
231 if (val > 9)
232 break;
233
234 ret = ret * 10 + val;
235 }
236
Willy Tarreau342acb42012-04-23 22:03:39 +0200237 smp->data.uint = ret;
Emeric Brun107ca302010-01-04 16:16:05 +0100238 return 1;
239}
240
241/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200242/* Sample casts matrix: */
243/* sample_casts[from type][to type] */
244/* NULL pointer used for impossible sample casts */
Emeric Brun107ca302010-01-04 16:16:05 +0100245/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100246
Willy Tarreau12785782012-04-27 21:37:17 +0200247typedef int (*sample_cast_fct)(struct sample *smp);
248static sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
Willy Tarreau422aa072012-04-20 20:49:27 +0200249/* to: BOOL UINT SINT IPV4 IPV6 STR BIN CSTR CBIN */
250/* from: BOOL */ { c_none, c_none, c_none, NULL, NULL, NULL, NULL, NULL, NULL },
251/* UINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
252/* SINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
253/* IPV4 */ { NULL, c_ip2int, c_ip2int, c_none, c_ip2ipv6, c_ip2str, NULL, c_ip2str, NULL },
254/* IPV6 */ { NULL, NULL, NULL, NULL, c_none, c_ipv62str, NULL, c_ipv62str, NULL },
255/* STR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_none, c_none, c_none, c_none },
256/* BIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_none, NULL, c_none },
257/* CSTR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_datadup, c_datadup, c_none, c_none },
258/* CBIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_datadup, NULL, c_none },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200259};
Emeric Brun107ca302010-01-04 16:16:05 +0100260
Emeric Brun107ca302010-01-04 16:16:05 +0100261/*
Willy Tarreau12785782012-04-27 21:37:17 +0200262 * Parse a sample expression configuration:
Emeric Brun107ca302010-01-04 16:16:05 +0100263 * fetch keyword followed by format conversion keywords.
Willy Tarreau12785782012-04-27 21:37:17 +0200264 * Returns a pointer on allocated sample expression structure.
Emeric Brun107ca302010-01-04 16:16:05 +0100265 */
Willy Tarreau12785782012-04-27 21:37:17 +0200266struct sample_expr *sample_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100267{
268 const char *endw;
269 const char *end;
Willy Tarreau12785782012-04-27 21:37:17 +0200270 struct sample_expr *expr;
271 struct sample_fetch *fetch;
272 struct sample_conv *conv;
Emeric Brun107ca302010-01-04 16:16:05 +0100273 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200274 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100275
Emeric Brun485479d2010-09-23 18:02:19 +0200276 snprintf(err, err_size, "memory error.");
277 if (!str[*idx]) {
278
279 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100280 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200281 }
Emeric Brun107ca302010-01-04 16:16:05 +0100282
283 end = str[*idx] + strlen(str[*idx]);
284 endw = strchr(str[*idx], '(');
285
286 if (!endw)
287 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200288 else if ((end-1)[0] != ')') {
289 p = my_strndup(str[*idx], endw - str[*idx]);
290 if (p) {
291 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
292 free(p);
293 }
Emeric Brun107ca302010-01-04 16:16:05 +0100294 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200295 }
Emeric Brun107ca302010-01-04 16:16:05 +0100296
Willy Tarreau12785782012-04-27 21:37:17 +0200297 fetch = find_sample_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200298 if (!fetch) {
299 p = my_strndup(str[*idx], endw - str[*idx]);
300 if (p) {
301 snprintf(err, err_size, "unknown fetch method '%s'.", p);
302 free(p);
303 }
Emeric Brun107ca302010-01-04 16:16:05 +0100304 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200305 }
Willy Tarreau422aa072012-04-20 20:49:27 +0200306 if (fetch->out_type >= SMP_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100307
Emeric Brun485479d2010-09-23 18:02:19 +0200308 p = my_strndup(str[*idx], endw - str[*idx]);
309 if (p) {
310 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
311 free(p);
312 }
Emeric Brun107ca302010-01-04 16:16:05 +0100313 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200314 }
Emeric Brun107ca302010-01-04 16:16:05 +0100315
316 prev_type = fetch->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200317 expr = calloc(1, sizeof(struct sample_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200318 if (!expr)
319 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100320
321 LIST_INIT(&(expr->conv_exprs));
322 expr->fetch = fetch;
323
324 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200325 char *err_msg = NULL;
326 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200327
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200328 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200329 p = my_strndup(str[*idx], endw - str[*idx]);
330 if (p) {
331 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
332 free(p);
333 }
334 goto out_error;
335 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200336
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200337 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 +0200338 p = my_strndup(str[*idx], endw - str[*idx]);
339 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200340 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 +0200341 free(p);
342 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200343 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200344 goto out_error;
345 }
346
347 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
348 p = my_strndup(str[*idx], endw - str[*idx]);
349 if (p) {
350 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
351 free(p);
352 }
353 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200354 goto out_error;
355 }
356 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200357 else if (fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200358 p = my_strndup(str[*idx], endw - str[*idx]);
359 if (p) {
360 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
361 free(p);
362 }
363 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100364 }
365
366 for (*idx += 1; *(str[*idx]); (*idx)++) {
Willy Tarreau12785782012-04-27 21:37:17 +0200367 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100368
369 end = str[*idx] + strlen(str[*idx]);
370 endw = strchr(str[*idx], '(');
371
372 if (!endw)
373 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200374 else if ((end-1)[0] != ')') {
375 p = my_strndup(str[*idx], endw - str[*idx]);
376 if (p) {
377 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
378 free(p);
379 }
Emeric Brun107ca302010-01-04 16:16:05 +0100380 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200381 }
Emeric Brun107ca302010-01-04 16:16:05 +0100382
Willy Tarreau12785782012-04-27 21:37:17 +0200383 conv = find_sample_conv(str[*idx], endw - str[*idx]);
Emeric Brun107ca302010-01-04 16:16:05 +0100384 if (!conv)
385 break;
386
Willy Tarreau422aa072012-04-20 20:49:27 +0200387 if (conv->in_type >= SMP_TYPES ||
388 conv->out_type >= SMP_TYPES) {
Emeric Brun485479d2010-09-23 18:02:19 +0200389 p = my_strndup(str[*idx], endw - str[*idx]);
390 if (p) {
391 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
392 free(p);
393 }
Emeric Brun107ca302010-01-04 16:16:05 +0100394 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200395 }
Emeric Brun107ca302010-01-04 16:16:05 +0100396
397 /* If impossible type conversion */
Willy Tarreau12785782012-04-27 21:37:17 +0200398 if (!sample_casts[prev_type][conv->in_type]) {
Emeric Brun485479d2010-09-23 18:02:19 +0200399 p = my_strndup(str[*idx], endw - str[*idx]);
400 if (p) {
401 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
402 free(p);
403 }
Emeric Brun107ca302010-01-04 16:16:05 +0100404 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200405 }
Emeric Brun107ca302010-01-04 16:16:05 +0100406
407 prev_type = conv->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200408 conv_expr = calloc(1, sizeof(struct sample_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200409 if (!conv_expr)
410 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100411
412 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
413 conv_expr->conv = conv;
414
415 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200416 char *err_msg = NULL;
417 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200418
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200419 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200420 p = my_strndup(str[*idx], endw - str[*idx]);
421
422 if (p) {
423 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
424 free(p);
425 }
426 goto out_error;
427 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100428
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200429 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 +0200430 p = my_strndup(str[*idx], endw - str[*idx]);
431 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200432 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 +0200433 free(p);
434 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200435 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200436 goto out_error;
437 }
438
439 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
440 p = my_strndup(str[*idx], endw - str[*idx]);
441 if (p) {
442 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
443 free(p);
444 }
445 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200446 goto out_error;
447 }
448 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200449 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200450 p = my_strndup(str[*idx], endw - str[*idx]);
451 if (p) {
452 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100453 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100454 }
Emeric Brun485479d2010-09-23 18:02:19 +0200455 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100456 }
Emeric Brun485479d2010-09-23 18:02:19 +0200457
Emeric Brun107ca302010-01-04 16:16:05 +0100458 }
Emeric Brun485479d2010-09-23 18:02:19 +0200459
Emeric Brun107ca302010-01-04 16:16:05 +0100460 return expr;
461
462out_error:
Willy Tarreau12785782012-04-27 21:37:17 +0200463 /* TODO: prune_sample_expr(expr); */
Emeric Brun107ca302010-01-04 16:16:05 +0100464 return NULL;
465}
466
467/*
Willy Tarreau12785782012-04-27 21:37:17 +0200468 * Process a fetch + format conversion of defined by the sample expression <expr>
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200469 * on request or response considering the <opt> parameter.
Willy Tarreau12785782012-04-27 21:37:17 +0200470 * Returns a pointer on a typed sample structure containing the result or NULL if
471 * sample is not found or when format conversion failed.
Emeric Brun107ca302010-01-04 16:16:05 +0100472 * If <p> is not null, function returns results in structure pointed by <p>.
Willy Tarreau12785782012-04-27 21:37:17 +0200473 * If <p> is null, functions returns a pointer on a static sample structure.
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200474 *
475 * Note: the fetch functions are required to properly set the return type. The
476 * conversion functions must do so too. However the cast functions do not need
477 * to since they're made to cast mutiple types according to what is required.
Emeric Brun107ca302010-01-04 16:16:05 +0100478 */
Willy Tarreau12785782012-04-27 21:37:17 +0200479struct sample *sample_process(struct proxy *px, struct session *l4, void *l7,
480 unsigned int opt,
481 struct sample_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100482{
Willy Tarreau12785782012-04-27 21:37:17 +0200483 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100484
485 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200486 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100487
Willy Tarreau342acb42012-04-23 22:03:39 +0200488 p->flags = 0;
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200489 if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100490 return NULL;
491
Willy Tarreau40aebd92012-04-26 11:05:50 +0200492 if (p->flags & SMP_F_MAY_CHANGE)
Willy Tarreau12785782012-04-27 21:37:17 +0200493 return NULL; /* we can only use stable samples */
Willy Tarreau40aebd92012-04-26 11:05:50 +0200494
Emeric Brun107ca302010-01-04 16:16:05 +0100495 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
Willy Tarreau12e50112012-04-25 17:21:49 +0200496 /* we want to ensure that p->type can be casted into
497 * conv_expr->conv->in_type. We have 3 possibilities :
498 * - NULL => not castable.
499 * - c_none => nothing to do (let's optimize it)
500 * - other => apply cast and prepare to fail
501 */
Willy Tarreau12785782012-04-27 21:37:17 +0200502 if (!sample_casts[p->type][conv_expr->conv->in_type])
Willy Tarreau12e50112012-04-25 17:21:49 +0200503 return NULL;
504
Willy Tarreau12785782012-04-27 21:37:17 +0200505 if (sample_casts[p->type][conv_expr->conv->in_type] != c_none &&
506 !sample_casts[p->type][conv_expr->conv->in_type](p))
Emeric Brun107ca302010-01-04 16:16:05 +0100507 return NULL;
508
Willy Tarreau12e50112012-04-25 17:21:49 +0200509 /* OK cast succeeded */
510
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200511 /* force the output type after a cast */
Emeric Brun107ca302010-01-04 16:16:05 +0100512 p->type = conv_expr->conv->in_type;
Willy Tarreau342acb42012-04-23 22:03:39 +0200513 if (!conv_expr->conv->process(conv_expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100514 return NULL;
Emeric Brun107ca302010-01-04 16:16:05 +0100515 }
516 return p;
517}
518
Emeric Brun107ca302010-01-04 16:16:05 +0100519/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200520/* Sample format convert functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200521/* These functions set the data type on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100522/*****************************************************************/
523
Willy Tarreau12785782012-04-27 21:37:17 +0200524static int sample_conv_str2lower(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100525{
526 int i;
527
Willy Tarreau342acb42012-04-23 22:03:39 +0200528 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200529 return 0;
530
Willy Tarreau342acb42012-04-23 22:03:39 +0200531 for (i = 0; i < smp->data.str.len; i++) {
532 if ((smp->data.str.str[i] >= 'A') && (smp->data.str.str[i] <= 'Z'))
533 smp->data.str.str[i] += 'a' - 'A';
Emeric Brun107ca302010-01-04 16:16:05 +0100534 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200535 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100536 return 1;
537}
538
Willy Tarreau12785782012-04-27 21:37:17 +0200539static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100540{
541 int i;
542
Willy Tarreau342acb42012-04-23 22:03:39 +0200543 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200544 return 0;
545
Willy Tarreau342acb42012-04-23 22:03:39 +0200546 for (i = 0; i < smp->data.str.len; i++) {
547 if ((smp->data.str.str[i] >= 'a') && (smp->data.str.str[i] <= 'z'))
548 smp->data.str.str[i] += 'A' - 'a';
Emeric Brun107ca302010-01-04 16:16:05 +0100549 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200550 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100551 return 1;
552}
553
Willy Tarreauf9954102012-04-20 14:03:29 +0200554/* takes the netmask in arg_p */
Willy Tarreau12785782012-04-27 21:37:17 +0200555static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100556{
Willy Tarreau342acb42012-04-23 22:03:39 +0200557 smp->data.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200558 smp->type = SMP_T_IPV4;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100559 return 1;
560}
561
Emeric Brun107ca302010-01-04 16:16:05 +0100562/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreau12785782012-04-27 21:37:17 +0200563static struct sample_conv_kw_list sample_conv_kws = {{ },{
564 { "upper", sample_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
565 { "lower", sample_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
566 { "ipmask", sample_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200567 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100568}};
569
570__attribute__((constructor))
Willy Tarreau12785782012-04-27 21:37:17 +0200571static void __sample_init(void)
Emeric Brun107ca302010-01-04 16:16:05 +0100572{
Willy Tarreau12785782012-04-27 21:37:17 +0200573 /* register sample format convert keywords */
574 sample_register_convs(&sample_conv_kws);
Emeric Brun107ca302010-01-04 16:16:05 +0100575}