blob: 10e136560a1ca86522870659bfbc97e37a9166d9 [file] [log] [blame]
Emeric Brun107ca302010-01-04 16:16:05 +01001/*
2 * Patterns management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <string.h>
14#include <arpa/inet.h>
Emeric Brun107ca302010-01-04 16:16:05 +010015
Willy Tarreau9fcb9842012-04-20 14:45:49 +020016#include <proto/arg.h>
Emeric Brun107ca302010-01-04 16:16:05 +010017#include <proto/pattern.h>
Emeric Brun485479d2010-09-23 18:02:19 +020018#include <proto/buffers.h>
Emeric Brun107ca302010-01-04 16:16:05 +010019#include <common/standard.h>
20
Willy Tarreaub4a88f02012-04-23 21:35:11 +020021/* static sample used in pattern_process() when <p> is NULL */
22static struct sample temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +010023
24/* trash chunk used for pattern conversions */
25static struct chunk trash_chunk;
26
27/* trash buffers used or pattern conversions */
28static char pattern_trash_buf1[BUFSIZE];
29static char pattern_trash_buf2[BUFSIZE];
30
31/* pattern_trash_buf point on used buffer*/
32static char *pattern_trash_buf = pattern_trash_buf1;
33
Emeric Brun107ca302010-01-04 16:16:05 +010034/* list head of all known pattern fetch keywords */
35static struct pattern_fetch_kw_list pattern_fetches = {
36 .list = LIST_HEAD_INIT(pattern_fetches.list)
37};
38
39/* list head of all known pattern format conversion keywords */
40static struct pattern_conv_kw_list pattern_convs = {
41 .list = LIST_HEAD_INIT(pattern_convs.list)
42};
43
44/*
45 * Registers the pattern fetch keyword list <kwl> as a list of valid keywords for next
46 * parsing sessions.
47 */
48void pattern_register_fetches(struct pattern_fetch_kw_list *pfkl)
49{
50 LIST_ADDQ(&pattern_fetches.list, &pfkl->list);
51}
52
53/*
54 * Registers the pattern format coverstion keyword list <pckl> as a list of valid keywords for next
55 * parsing sessions.
56 */
57void pattern_register_convs(struct pattern_conv_kw_list *pckl)
58{
59 LIST_ADDQ(&pattern_convs.list, &pckl->list);
60}
61
62/*
63 * Returns the pointer on pattern fetch keyword structure identified by
64 * string of <len> in buffer <kw>.
65 *
66 */
67struct pattern_fetch *find_pattern_fetch(const char *kw, int len)
68{
69 int index;
70 struct pattern_fetch_kw_list *kwl;
71
72 list_for_each_entry(kwl, &pattern_fetches.list, list) {
73 for (index = 0; kwl->kw[index].kw != NULL; index++) {
74 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
75 kwl->kw[index].kw[len] == '\0')
76 return &kwl->kw[index];
77 }
78 }
79 return NULL;
80}
81
82/*
83 * Returns the pointer on pattern format conversion keyword structure identified by
84 * string of <len> in buffer <kw>.
85 *
86 */
87struct pattern_conv *find_pattern_conv(const char *kw, int len)
88{
89 int index;
90 struct pattern_conv_kw_list *kwl;
91
92 list_for_each_entry(kwl, &pattern_convs.list, list) {
93 for (index = 0; kwl->kw[index].kw != NULL; index++) {
94 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
95 kwl->kw[index].kw[len] == '\0')
96 return &kwl->kw[index];
97 }
98 }
99 return NULL;
100}
101
102
103/*
104* Returns a static trash struct chunk to use in pattern casts or format conversions
105* Swiths the 2 available trash buffers to protect data during convert
106*/
107static struct chunk *get_trash_chunk(void)
108{
109 if (pattern_trash_buf == pattern_trash_buf1)
110 pattern_trash_buf = pattern_trash_buf2;
111 else
112 pattern_trash_buf = pattern_trash_buf1;
113
Emeric Brun485479d2010-09-23 18:02:19 +0200114 chunk_init(&trash_chunk, pattern_trash_buf, BUFSIZE);
Emeric Brun107ca302010-01-04 16:16:05 +0100115
116 return &trash_chunk;
117}
118
Emeric Brun107ca302010-01-04 16:16:05 +0100119/******************************************************************/
120/* Pattern casts functions */
121/******************************************************************/
122
123static int c_ip2int(union pattern_data *data)
124{
Willy Tarreau422aa072012-04-20 20:49:27 +0200125 data->uint = ntohl(data->ipv4.s_addr);
Emeric Brun107ca302010-01-04 16:16:05 +0100126 return 1;
127}
128
129static int c_ip2str(union pattern_data *data)
130{
131 struct chunk *trash = get_trash_chunk();
132
Willy Tarreau422aa072012-04-20 20:49:27 +0200133 if (!inet_ntop(AF_INET, (void *)&data->ipv4, trash->str, trash->size))
Emeric Brun107ca302010-01-04 16:16:05 +0100134 return 0;
135
136 trash->len = strlen(trash->str);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100137 data->str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100138
139 return 1;
140}
141
David du Colombier4f92d322011-03-24 11:09:31 +0100142static int c_ip2ipv6(union pattern_data *data)
143{
Willy Tarreau422aa072012-04-20 20:49:27 +0200144 v4tov6(&data->ipv6, &data->ipv4);
David du Colombier4f92d322011-03-24 11:09:31 +0100145 return 1;
146}
147
148static int c_ipv62str(union pattern_data *data)
149{
150 struct chunk *trash = get_trash_chunk();
151
152 if (!inet_ntop(AF_INET6, (void *)&data->ipv6, trash->str, trash->size))
153 return 0;
154
155 trash->len = strlen(trash->str);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100156 data->str = *trash;
David du Colombier4f92d322011-03-24 11:09:31 +0100157 return 1;
158}
159
160/*
161static int c_ipv62ip(union pattern_data *data)
162{
Willy Tarreau422aa072012-04-20 20:49:27 +0200163 return v6tov4(&data->ipv4, &data->ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100164}
165*/
166
Emeric Brun107ca302010-01-04 16:16:05 +0100167static int c_int2ip(union pattern_data *data)
168{
Willy Tarreau422aa072012-04-20 20:49:27 +0200169 data->ipv4.s_addr = htonl(data->uint);
Emeric Brun107ca302010-01-04 16:16:05 +0100170 return 1;
171}
172
Emeric Brun107ca302010-01-04 16:16:05 +0100173static int c_str2ip(union pattern_data *data)
174{
Willy Tarreau422aa072012-04-20 20:49:27 +0200175 if (!buf2ip(data->str.str, data->str.len, &data->ipv4))
Emeric Brun107ca302010-01-04 16:16:05 +0100176 return 0;
177 return 1;
178}
179
David du Colombier4f92d322011-03-24 11:09:31 +0100180static int c_str2ipv6(union pattern_data *data)
181{
182 return inet_pton(AF_INET6, data->str.str, &data->ipv6);
183}
184
Emeric Brun107ca302010-01-04 16:16:05 +0100185static int c_int2str(union pattern_data *data)
186{
187 struct chunk *trash = get_trash_chunk();
188 char *pos;
189
Willy Tarreau422aa072012-04-20 20:49:27 +0200190 pos = ultoa_r(data->uint, trash->str, trash->size);
Emeric Brun107ca302010-01-04 16:16:05 +0100191
192 if (!pos)
193 return 0;
194
Emeric Brun485479d2010-09-23 18:02:19 +0200195 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100196 trash->str = pos;
197 trash->len = strlen(pos);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100198 data->str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100199 return 1;
200}
201
Emeric Brun485479d2010-09-23 18:02:19 +0200202static int c_datadup(union pattern_data *data)
203{
204 struct chunk *trash = get_trash_chunk();
205
206 trash->len = data->str.len < trash->size ? data->str.len : trash->size;
207 memcpy(trash->str, data->str.str, trash->len);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100208 data->str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200209 return 1;
210}
211
212
Willy Tarreau422aa072012-04-20 20:49:27 +0200213static int c_none(union pattern_data *data)
Emeric Brun107ca302010-01-04 16:16:05 +0100214{
215 return 1;
216}
217
218static int c_str2int(union pattern_data *data)
219{
220 int i;
221 uint32_t ret = 0;
222
223 for (i = 0; i < data->str.len; i++) {
224 uint32_t val = data->str.str[i] - '0';
225
226 if (val > 9)
227 break;
228
229 ret = ret * 10 + val;
230 }
231
Willy Tarreau422aa072012-04-20 20:49:27 +0200232 data->uint = ret;
Emeric Brun107ca302010-01-04 16:16:05 +0100233 return 1;
234}
235
236/*****************************************************************/
237/* Pattern casts matrix: */
238/* pattern_casts[from type][to type] */
239/* NULL pointer used for impossible pattern casts */
240/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100241
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200242typedef int (*pattern_cast_fct)(union pattern_data *data);
Willy Tarreau422aa072012-04-20 20:49:27 +0200243static pattern_cast_fct pattern_casts[SMP_TYPES][SMP_TYPES] = {
244/* to: BOOL UINT SINT IPV4 IPV6 STR BIN CSTR CBIN */
245/* from: BOOL */ { c_none, c_none, c_none, NULL, NULL, NULL, NULL, NULL, NULL },
246/* UINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
247/* SINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
248/* IPV4 */ { NULL, c_ip2int, c_ip2int, c_none, c_ip2ipv6, c_ip2str, NULL, c_ip2str, NULL },
249/* IPV6 */ { NULL, NULL, NULL, NULL, c_none, c_ipv62str, NULL, c_ipv62str, NULL },
250/* STR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_none, c_none, c_none, c_none },
251/* BIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_none, NULL, c_none },
252/* CSTR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_datadup, c_datadup, c_none, c_none },
253/* CBIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_datadup, NULL, c_none },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200254};
Emeric Brun107ca302010-01-04 16:16:05 +0100255
Emeric Brun107ca302010-01-04 16:16:05 +0100256/*
257 * Parse a pattern expression configuration:
258 * fetch keyword followed by format conversion keywords.
259 * Returns a pointer on allocated pattern expression structure.
260 */
Emeric Brun485479d2010-09-23 18:02:19 +0200261struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100262{
263 const char *endw;
264 const char *end;
265 struct pattern_expr *expr;
266 struct pattern_fetch *fetch;
267 struct pattern_conv *conv;
268 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200269 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100270
Emeric Brun485479d2010-09-23 18:02:19 +0200271 snprintf(err, err_size, "memory error.");
272 if (!str[*idx]) {
273
274 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100275 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200276 }
Emeric Brun107ca302010-01-04 16:16:05 +0100277
278 end = str[*idx] + strlen(str[*idx]);
279 endw = strchr(str[*idx], '(');
280
281 if (!endw)
282 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200283 else if ((end-1)[0] != ')') {
284 p = my_strndup(str[*idx], endw - str[*idx]);
285 if (p) {
286 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
287 free(p);
288 }
Emeric Brun107ca302010-01-04 16:16:05 +0100289 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200290 }
Emeric Brun107ca302010-01-04 16:16:05 +0100291
292 fetch = find_pattern_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200293 if (!fetch) {
294 p = my_strndup(str[*idx], endw - str[*idx]);
295 if (p) {
296 snprintf(err, err_size, "unknown fetch method '%s'.", p);
297 free(p);
298 }
Emeric Brun107ca302010-01-04 16:16:05 +0100299 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200300 }
Willy Tarreau422aa072012-04-20 20:49:27 +0200301 if (fetch->out_type >= SMP_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100302
Emeric Brun485479d2010-09-23 18:02:19 +0200303 p = my_strndup(str[*idx], endw - str[*idx]);
304 if (p) {
305 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
306 free(p);
307 }
Emeric Brun107ca302010-01-04 16:16:05 +0100308 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200309 }
Emeric Brun107ca302010-01-04 16:16:05 +0100310
311 prev_type = fetch->out_type;
312 expr = calloc(1, sizeof(struct pattern_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200313 if (!expr)
314 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100315
316 LIST_INIT(&(expr->conv_exprs));
317 expr->fetch = fetch;
318
319 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200320 char *err_msg = NULL;
321 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200322
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200323 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200324 p = my_strndup(str[*idx], endw - str[*idx]);
325 if (p) {
326 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
327 free(p);
328 }
329 goto out_error;
330 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200331
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200332 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 +0200333 p = my_strndup(str[*idx], endw - str[*idx]);
334 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200335 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 +0200336 free(p);
337 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200338 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200339 goto out_error;
340 }
341
342 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 Tarreau9fcb9842012-04-20 14:45:49 +0200352 else if (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)++) {
362 struct pattern_conv_expr *conv_expr;
363
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
378 conv = find_pattern_conv(str[*idx], endw - str[*idx]);
379 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 */
Emeric Brun485479d2010-09-23 18:02:19 +0200393 if (!pattern_casts[prev_type][conv->in_type]) {
394 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;
403 conv_expr = calloc(1, sizeof(struct pattern_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
434 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
435 p = my_strndup(str[*idx], endw - str[*idx]);
436 if (p) {
437 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
438 free(p);
439 }
440 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200441 goto out_error;
442 }
443 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200444 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200445 p = my_strndup(str[*idx], endw - str[*idx]);
446 if (p) {
447 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100448 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100449 }
Emeric Brun485479d2010-09-23 18:02:19 +0200450 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100451 }
Emeric Brun485479d2010-09-23 18:02:19 +0200452
Emeric Brun107ca302010-01-04 16:16:05 +0100453 }
Emeric Brun485479d2010-09-23 18:02:19 +0200454
Emeric Brun107ca302010-01-04 16:16:05 +0100455 return expr;
456
457out_error:
458 /* TODO: prune_pattern_expr(expr); */
459 return NULL;
460}
461
462/*
463 * Process a fetch + format conversion of defined by the pattern expression <expr>
464 * on request or response considering the <dir> parameter.
465 * Returns a pointer on a typed pattern structure containing the result or NULL if
466 * pattern is not found or when format conversion failed.
467 * If <p> is not null, function returns results in structure pointed by <p>.
468 * If <p> is null, functions returns a pointer on a static pattern structure.
469 */
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200470struct sample *pattern_process(struct proxy *px, struct session *l4, void *l7, int dir,
471 struct pattern_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100472{
473 struct pattern_conv_expr *conv_expr;
474
475 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200476 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100477
Willy Tarreauf9954102012-04-20 14:03:29 +0200478 if (!expr->fetch->process(px, l4, l7, dir, expr->arg_p, &p->data))
Emeric Brun107ca302010-01-04 16:16:05 +0100479 return NULL;
480
481 p->type = expr->fetch->out_type;
482
483 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
484 if (!pattern_casts[p->type][conv_expr->conv->in_type](&p->data))
485 return NULL;
486
487 p->type = conv_expr->conv->in_type;
Willy Tarreauf9954102012-04-20 14:03:29 +0200488 if (!conv_expr->conv->process(conv_expr->arg_p, &p->data))
Emeric Brun107ca302010-01-04 16:16:05 +0100489 return NULL;
490
491 p->type = conv_expr->conv->out_type;
492 }
493 return p;
494}
495
Emeric Brun107ca302010-01-04 16:16:05 +0100496/*****************************************************************/
497/* Pattern format convert functions */
498/*****************************************************************/
499
Willy Tarreauf9954102012-04-20 14:03:29 +0200500static int pattern_conv_str2lower(const struct arg *arg_p, union pattern_data *data)
Emeric Brun107ca302010-01-04 16:16:05 +0100501{
502 int i;
503
Emeric Brun485479d2010-09-23 18:02:19 +0200504 if (!data->str.size)
505 return 0;
506
Emeric Brun107ca302010-01-04 16:16:05 +0100507 for (i = 0; i < data->str.len; i++) {
508 if ((data->str.str[i] >= 'A') && (data->str.str[i] <= 'Z'))
509 data->str.str[i] += 'a' - 'A';
510 }
511 return 1;
512}
513
Willy Tarreauf9954102012-04-20 14:03:29 +0200514static int pattern_conv_str2upper(const struct arg *arg_p, union pattern_data *data)
Emeric Brun107ca302010-01-04 16:16:05 +0100515{
516 int i;
517
Emeric Brun485479d2010-09-23 18:02:19 +0200518 if (!data->str.size)
519 return 0;
520
Emeric Brun107ca302010-01-04 16:16:05 +0100521 for (i = 0; i < data->str.len; i++) {
522 if ((data->str.str[i] >= 'a') && (data->str.str[i] <= 'z'))
523 data->str.str[i] += 'A' - 'a';
524 }
525 return 1;
526}
527
Willy Tarreauf9954102012-04-20 14:03:29 +0200528/* takes the netmask in arg_p */
529static int pattern_conv_ipmask(const struct arg *arg_p, union pattern_data *data)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100530{
Willy Tarreau422aa072012-04-20 20:49:27 +0200531 data->ipv4.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100532 return 1;
533}
534
Emeric Brun107ca302010-01-04 16:16:05 +0100535/* Note: must not be declared <const> as its list will be overwritten */
536static struct pattern_conv_kw_list pattern_conv_kws = {{ },{
Willy Tarreau422aa072012-04-20 20:49:27 +0200537 { "upper", pattern_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
538 { "lower", pattern_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
539 { "ipmask", pattern_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200540 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100541}};
542
543__attribute__((constructor))
544static void __pattern_init(void)
545{
546 /* register pattern format convert keywords */
547 pattern_register_convs(&pattern_conv_kws);
548}