blob: 3eef4c3342833c72a6c925b8b5a37669075cdcce [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;
Willy Tarreau2e845be2012-10-19 19:49:09 +0200323 expr->arg_p = empty_arg_list;
Emeric Brun107ca302010-01-04 16:16:05 +0100324
325 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200326 char *err_msg = NULL;
327 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200328
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200329 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200330 p = my_strndup(str[*idx], endw - str[*idx]);
331 if (p) {
332 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
333 free(p);
334 }
335 goto out_error;
336 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200337
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200338 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 +0200339 p = my_strndup(str[*idx], endw - str[*idx]);
340 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200341 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 +0200342 free(p);
343 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200344 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200345 goto out_error;
346 }
347
Willy Tarreau2e845be2012-10-19 19:49:09 +0200348 if (!expr->arg_p)
349 expr->arg_p = empty_arg_list;
350
Willy Tarreau21d68a62012-04-20 15:52:36 +0200351 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
352 p = my_strndup(str[*idx], endw - str[*idx]);
353 if (p) {
354 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
355 free(p);
356 }
357 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200358 goto out_error;
359 }
360 }
Willy Tarreauf22a5082012-10-19 16:47:23 +0200361 else if (ARGM(fetch->arg_mask)) {
Emeric Brun485479d2010-09-23 18:02:19 +0200362 p = my_strndup(str[*idx], endw - str[*idx]);
363 if (p) {
364 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
365 free(p);
366 }
367 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100368 }
369
370 for (*idx += 1; *(str[*idx]); (*idx)++) {
Willy Tarreau12785782012-04-27 21:37:17 +0200371 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100372
373 end = str[*idx] + strlen(str[*idx]);
374 endw = strchr(str[*idx], '(');
375
376 if (!endw)
377 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200378 else if ((end-1)[0] != ')') {
379 p = my_strndup(str[*idx], endw - str[*idx]);
380 if (p) {
381 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
382 free(p);
383 }
Emeric Brun107ca302010-01-04 16:16:05 +0100384 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200385 }
Emeric Brun107ca302010-01-04 16:16:05 +0100386
Willy Tarreau12785782012-04-27 21:37:17 +0200387 conv = find_sample_conv(str[*idx], endw - str[*idx]);
Emeric Brun107ca302010-01-04 16:16:05 +0100388 if (!conv)
389 break;
390
Willy Tarreau422aa072012-04-20 20:49:27 +0200391 if (conv->in_type >= SMP_TYPES ||
392 conv->out_type >= SMP_TYPES) {
Emeric Brun485479d2010-09-23 18:02:19 +0200393 p = my_strndup(str[*idx], endw - str[*idx]);
394 if (p) {
395 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
396 free(p);
397 }
Emeric Brun107ca302010-01-04 16:16:05 +0100398 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200399 }
Emeric Brun107ca302010-01-04 16:16:05 +0100400
401 /* If impossible type conversion */
Willy Tarreau12785782012-04-27 21:37:17 +0200402 if (!sample_casts[prev_type][conv->in_type]) {
Emeric Brun485479d2010-09-23 18:02:19 +0200403 p = my_strndup(str[*idx], endw - str[*idx]);
404 if (p) {
405 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
406 free(p);
407 }
Emeric Brun107ca302010-01-04 16:16:05 +0100408 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200409 }
Emeric Brun107ca302010-01-04 16:16:05 +0100410
411 prev_type = conv->out_type;
Willy Tarreau12785782012-04-27 21:37:17 +0200412 conv_expr = calloc(1, sizeof(struct sample_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200413 if (!conv_expr)
414 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100415
416 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
417 conv_expr->conv = conv;
418
419 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200420 char *err_msg = NULL;
421 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200422
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200423 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200424 p = my_strndup(str[*idx], endw - str[*idx]);
425
426 if (p) {
427 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
428 free(p);
429 }
430 goto out_error;
431 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100432
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200433 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 +0200434 p = my_strndup(str[*idx], endw - str[*idx]);
435 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200436 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 +0200437 free(p);
438 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200439 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200440 goto out_error;
441 }
442
Willy Tarreau2e845be2012-10-19 19:49:09 +0200443 if (!conv_expr->arg_p)
444 conv_expr->arg_p = empty_arg_list;
445
Willy Tarreau21d68a62012-04-20 15:52:36 +0200446 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
447 p = my_strndup(str[*idx], endw - str[*idx]);
448 if (p) {
449 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
450 free(p);
451 }
452 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200453 goto out_error;
454 }
455 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200456 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200457 p = my_strndup(str[*idx], endw - str[*idx]);
458 if (p) {
459 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100460 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100461 }
Emeric Brun485479d2010-09-23 18:02:19 +0200462 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100463 }
Emeric Brun485479d2010-09-23 18:02:19 +0200464
Emeric Brun107ca302010-01-04 16:16:05 +0100465 }
Emeric Brun485479d2010-09-23 18:02:19 +0200466
Emeric Brun107ca302010-01-04 16:16:05 +0100467 return expr;
468
469out_error:
Willy Tarreau12785782012-04-27 21:37:17 +0200470 /* TODO: prune_sample_expr(expr); */
Emeric Brun107ca302010-01-04 16:16:05 +0100471 return NULL;
472}
473
474/*
Willy Tarreau12785782012-04-27 21:37:17 +0200475 * Process a fetch + format conversion of defined by the sample expression <expr>
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200476 * on request or response considering the <opt> parameter.
Willy Tarreau12785782012-04-27 21:37:17 +0200477 * Returns a pointer on a typed sample structure containing the result or NULL if
478 * sample is not found or when format conversion failed.
Emeric Brun107ca302010-01-04 16:16:05 +0100479 * If <p> is not null, function returns results in structure pointed by <p>.
Willy Tarreau12785782012-04-27 21:37:17 +0200480 * If <p> is null, functions returns a pointer on a static sample structure.
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200481 *
482 * Note: the fetch functions are required to properly set the return type. The
483 * conversion functions must do so too. However the cast functions do not need
484 * to since they're made to cast mutiple types according to what is required.
Emeric Brun107ca302010-01-04 16:16:05 +0100485 */
Willy Tarreau12785782012-04-27 21:37:17 +0200486struct sample *sample_process(struct proxy *px, struct session *l4, void *l7,
487 unsigned int opt,
488 struct sample_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100489{
Willy Tarreau12785782012-04-27 21:37:17 +0200490 struct sample_conv_expr *conv_expr;
Emeric Brun107ca302010-01-04 16:16:05 +0100491
492 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200493 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100494
Willy Tarreau342acb42012-04-23 22:03:39 +0200495 p->flags = 0;
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200496 if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100497 return NULL;
498
Willy Tarreau40aebd92012-04-26 11:05:50 +0200499 if (p->flags & SMP_F_MAY_CHANGE)
Willy Tarreau12785782012-04-27 21:37:17 +0200500 return NULL; /* we can only use stable samples */
Willy Tarreau40aebd92012-04-26 11:05:50 +0200501
Emeric Brun107ca302010-01-04 16:16:05 +0100502 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
Willy Tarreau12e50112012-04-25 17:21:49 +0200503 /* we want to ensure that p->type can be casted into
504 * conv_expr->conv->in_type. We have 3 possibilities :
505 * - NULL => not castable.
506 * - c_none => nothing to do (let's optimize it)
507 * - other => apply cast and prepare to fail
508 */
Willy Tarreau12785782012-04-27 21:37:17 +0200509 if (!sample_casts[p->type][conv_expr->conv->in_type])
Willy Tarreau12e50112012-04-25 17:21:49 +0200510 return NULL;
511
Willy Tarreau12785782012-04-27 21:37:17 +0200512 if (sample_casts[p->type][conv_expr->conv->in_type] != c_none &&
513 !sample_casts[p->type][conv_expr->conv->in_type](p))
Emeric Brun107ca302010-01-04 16:16:05 +0100514 return NULL;
515
Willy Tarreau12e50112012-04-25 17:21:49 +0200516 /* OK cast succeeded */
517
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200518 /* force the output type after a cast */
Emeric Brun107ca302010-01-04 16:16:05 +0100519 p->type = conv_expr->conv->in_type;
Willy Tarreau342acb42012-04-23 22:03:39 +0200520 if (!conv_expr->conv->process(conv_expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100521 return NULL;
Emeric Brun107ca302010-01-04 16:16:05 +0100522 }
523 return p;
524}
525
Emeric Brun107ca302010-01-04 16:16:05 +0100526/*****************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +0200527/* Sample format convert functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200528/* These functions set the data type on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100529/*****************************************************************/
530
Willy Tarreau12785782012-04-27 21:37:17 +0200531static int sample_conv_str2lower(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100532{
533 int i;
534
Willy Tarreau342acb42012-04-23 22:03:39 +0200535 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200536 return 0;
537
Willy Tarreau342acb42012-04-23 22:03:39 +0200538 for (i = 0; i < smp->data.str.len; i++) {
539 if ((smp->data.str.str[i] >= 'A') && (smp->data.str.str[i] <= 'Z'))
540 smp->data.str.str[i] += 'a' - 'A';
Emeric Brun107ca302010-01-04 16:16:05 +0100541 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200542 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100543 return 1;
544}
545
Willy Tarreau12785782012-04-27 21:37:17 +0200546static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100547{
548 int i;
549
Willy Tarreau342acb42012-04-23 22:03:39 +0200550 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200551 return 0;
552
Willy Tarreau342acb42012-04-23 22:03:39 +0200553 for (i = 0; i < smp->data.str.len; i++) {
554 if ((smp->data.str.str[i] >= 'a') && (smp->data.str.str[i] <= 'z'))
555 smp->data.str.str[i] += 'A' - 'a';
Emeric Brun107ca302010-01-04 16:16:05 +0100556 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200557 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100558 return 1;
559}
560
Willy Tarreauf9954102012-04-20 14:03:29 +0200561/* takes the netmask in arg_p */
Willy Tarreau12785782012-04-27 21:37:17 +0200562static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100563{
Willy Tarreau342acb42012-04-23 22:03:39 +0200564 smp->data.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200565 smp->type = SMP_T_IPV4;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100566 return 1;
567}
568
Emeric Brun107ca302010-01-04 16:16:05 +0100569/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreau12785782012-04-27 21:37:17 +0200570static struct sample_conv_kw_list sample_conv_kws = {{ },{
571 { "upper", sample_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
572 { "lower", sample_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
573 { "ipmask", sample_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200574 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100575}};
576
577__attribute__((constructor))
Willy Tarreau12785782012-04-27 21:37:17 +0200578static void __sample_init(void)
Emeric Brun107ca302010-01-04 16:16:05 +0100579{
Willy Tarreau12785782012-04-27 21:37:17 +0200580 /* register sample format convert keywords */
581 sample_register_convs(&sample_conv_kws);
Emeric Brun107ca302010-01-04 16:16:05 +0100582}