blob: 2820cf60d65a336a45f919f555b30c79c2904b3e [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 */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200121/* Note: these functions do *NOT* set the output type on the */
122/* sample, the caller is responsible for doing this on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100123/******************************************************************/
124
Willy Tarreau342acb42012-04-23 22:03:39 +0200125static int c_ip2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100126{
Willy Tarreau342acb42012-04-23 22:03:39 +0200127 smp->data.uint = ntohl(smp->data.ipv4.s_addr);
Emeric Brun107ca302010-01-04 16:16:05 +0100128 return 1;
129}
130
Willy Tarreau342acb42012-04-23 22:03:39 +0200131static int c_ip2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100132{
133 struct chunk *trash = get_trash_chunk();
134
Willy Tarreau342acb42012-04-23 22:03:39 +0200135 if (!inet_ntop(AF_INET, (void *)&smp->data.ipv4, trash->str, trash->size))
Emeric Brun107ca302010-01-04 16:16:05 +0100136 return 0;
137
138 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200139 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100140
141 return 1;
142}
143
Willy Tarreau342acb42012-04-23 22:03:39 +0200144static int c_ip2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100145{
Willy Tarreau342acb42012-04-23 22:03:39 +0200146 v4tov6(&smp->data.ipv6, &smp->data.ipv4);
David du Colombier4f92d322011-03-24 11:09:31 +0100147 return 1;
148}
149
Willy Tarreau342acb42012-04-23 22:03:39 +0200150static int c_ipv62str(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100151{
152 struct chunk *trash = get_trash_chunk();
153
Willy Tarreau342acb42012-04-23 22:03:39 +0200154 if (!inet_ntop(AF_INET6, (void *)&smp->data.ipv6, trash->str, trash->size))
David du Colombier4f92d322011-03-24 11:09:31 +0100155 return 0;
156
157 trash->len = strlen(trash->str);
Willy Tarreau342acb42012-04-23 22:03:39 +0200158 smp->data.str = *trash;
David du Colombier4f92d322011-03-24 11:09:31 +0100159 return 1;
160}
161
162/*
Willy Tarreau342acb42012-04-23 22:03:39 +0200163static int c_ipv62ip(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100164{
Willy Tarreau342acb42012-04-23 22:03:39 +0200165 return v6tov4(&smp->data.ipv4, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100166}
167*/
168
Willy Tarreau342acb42012-04-23 22:03:39 +0200169static int c_int2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100170{
Willy Tarreau342acb42012-04-23 22:03:39 +0200171 smp->data.ipv4.s_addr = htonl(smp->data.uint);
Emeric Brun107ca302010-01-04 16:16:05 +0100172 return 1;
173}
174
Willy Tarreau342acb42012-04-23 22:03:39 +0200175static int c_str2ip(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100176{
Willy Tarreau342acb42012-04-23 22:03:39 +0200177 if (!buf2ip(smp->data.str.str, smp->data.str.len, &smp->data.ipv4))
Emeric Brun107ca302010-01-04 16:16:05 +0100178 return 0;
179 return 1;
180}
181
Willy Tarreau342acb42012-04-23 22:03:39 +0200182static int c_str2ipv6(struct sample *smp)
David du Colombier4f92d322011-03-24 11:09:31 +0100183{
Willy Tarreau342acb42012-04-23 22:03:39 +0200184 return inet_pton(AF_INET6, smp->data.str.str, &smp->data.ipv6);
David du Colombier4f92d322011-03-24 11:09:31 +0100185}
186
Willy Tarreau342acb42012-04-23 22:03:39 +0200187static int c_int2str(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100188{
189 struct chunk *trash = get_trash_chunk();
190 char *pos;
191
Willy Tarreau342acb42012-04-23 22:03:39 +0200192 pos = ultoa_r(smp->data.uint, trash->str, trash->size);
Emeric Brun107ca302010-01-04 16:16:05 +0100193
194 if (!pos)
195 return 0;
196
Emeric Brun485479d2010-09-23 18:02:19 +0200197 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100198 trash->str = pos;
199 trash->len = strlen(pos);
Willy Tarreau342acb42012-04-23 22:03:39 +0200200 smp->data.str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100201 return 1;
202}
203
Willy Tarreau342acb42012-04-23 22:03:39 +0200204static int c_datadup(struct sample *smp)
Emeric Brun485479d2010-09-23 18:02:19 +0200205{
206 struct chunk *trash = get_trash_chunk();
207
Willy Tarreau342acb42012-04-23 22:03:39 +0200208 trash->len = smp->data.str.len < trash->size ? smp->data.str.len : trash->size;
209 memcpy(trash->str, smp->data.str.str, trash->len);
210 smp->data.str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200211 return 1;
212}
213
214
Willy Tarreau342acb42012-04-23 22:03:39 +0200215static int c_none(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100216{
217 return 1;
218}
219
Willy Tarreau342acb42012-04-23 22:03:39 +0200220static int c_str2int(struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100221{
222 int i;
223 uint32_t ret = 0;
224
Willy Tarreau342acb42012-04-23 22:03:39 +0200225 for (i = 0; i < smp->data.str.len; i++) {
226 uint32_t val = smp->data.str.str[i] - '0';
Emeric Brun107ca302010-01-04 16:16:05 +0100227
228 if (val > 9)
229 break;
230
231 ret = ret * 10 + val;
232 }
233
Willy Tarreau342acb42012-04-23 22:03:39 +0200234 smp->data.uint = ret;
Emeric Brun107ca302010-01-04 16:16:05 +0100235 return 1;
236}
237
238/*****************************************************************/
239/* Pattern casts matrix: */
240/* pattern_casts[from type][to type] */
241/* NULL pointer used for impossible pattern casts */
242/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100243
Willy Tarreau342acb42012-04-23 22:03:39 +0200244typedef int (*pattern_cast_fct)(struct sample *smp);
Willy Tarreau422aa072012-04-20 20:49:27 +0200245static pattern_cast_fct pattern_casts[SMP_TYPES][SMP_TYPES] = {
246/* to: BOOL UINT SINT IPV4 IPV6 STR BIN CSTR CBIN */
247/* from: BOOL */ { c_none, c_none, c_none, NULL, NULL, NULL, NULL, NULL, NULL },
248/* UINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
249/* SINT */ { c_none, c_none, c_none, c_int2ip, NULL, c_int2str, NULL, c_int2str, NULL },
250/* IPV4 */ { NULL, c_ip2int, c_ip2int, c_none, c_ip2ipv6, c_ip2str, NULL, c_ip2str, NULL },
251/* IPV6 */ { NULL, NULL, NULL, NULL, c_none, c_ipv62str, NULL, c_ipv62str, NULL },
252/* STR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_none, c_none, c_none, c_none },
253/* BIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_none, NULL, c_none },
254/* CSTR */ { c_str2int, c_str2int, c_str2int, c_str2ip, c_str2ipv6, c_datadup, c_datadup, c_none, c_none },
255/* CBIN */ { NULL, NULL, NULL, NULL, NULL, NULL, c_datadup, NULL, c_none },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200256};
Emeric Brun107ca302010-01-04 16:16:05 +0100257
Emeric Brun107ca302010-01-04 16:16:05 +0100258/*
259 * Parse a pattern expression configuration:
260 * fetch keyword followed by format conversion keywords.
261 * Returns a pointer on allocated pattern expression structure.
262 */
Emeric Brun485479d2010-09-23 18:02:19 +0200263struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100264{
265 const char *endw;
266 const char *end;
267 struct pattern_expr *expr;
268 struct pattern_fetch *fetch;
269 struct pattern_conv *conv;
270 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200271 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100272
Emeric Brun485479d2010-09-23 18:02:19 +0200273 snprintf(err, err_size, "memory error.");
274 if (!str[*idx]) {
275
276 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100277 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200278 }
Emeric Brun107ca302010-01-04 16:16:05 +0100279
280 end = str[*idx] + strlen(str[*idx]);
281 endw = strchr(str[*idx], '(');
282
283 if (!endw)
284 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200285 else if ((end-1)[0] != ')') {
286 p = my_strndup(str[*idx], endw - str[*idx]);
287 if (p) {
288 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
289 free(p);
290 }
Emeric Brun107ca302010-01-04 16:16:05 +0100291 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200292 }
Emeric Brun107ca302010-01-04 16:16:05 +0100293
294 fetch = find_pattern_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200295 if (!fetch) {
296 p = my_strndup(str[*idx], endw - str[*idx]);
297 if (p) {
298 snprintf(err, err_size, "unknown fetch method '%s'.", p);
299 free(p);
300 }
Emeric Brun107ca302010-01-04 16:16:05 +0100301 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200302 }
Willy Tarreau422aa072012-04-20 20:49:27 +0200303 if (fetch->out_type >= SMP_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100304
Emeric Brun485479d2010-09-23 18:02:19 +0200305 p = my_strndup(str[*idx], endw - str[*idx]);
306 if (p) {
307 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
308 free(p);
309 }
Emeric Brun107ca302010-01-04 16:16:05 +0100310 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200311 }
Emeric Brun107ca302010-01-04 16:16:05 +0100312
313 prev_type = fetch->out_type;
314 expr = calloc(1, sizeof(struct pattern_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200315 if (!expr)
316 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100317
318 LIST_INIT(&(expr->conv_exprs));
319 expr->fetch = fetch;
320
321 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200322 char *err_msg = NULL;
323 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200324
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200325 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200326 p = my_strndup(str[*idx], endw - str[*idx]);
327 if (p) {
328 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
329 free(p);
330 }
331 goto out_error;
332 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200333
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200334 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 +0200335 p = my_strndup(str[*idx], endw - str[*idx]);
336 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200337 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 +0200338 free(p);
339 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200340 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200341 goto out_error;
342 }
343
344 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
345 p = my_strndup(str[*idx], endw - str[*idx]);
346 if (p) {
347 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
348 free(p);
349 }
350 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200351 goto out_error;
352 }
353 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200354 else if (fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200355 p = my_strndup(str[*idx], endw - str[*idx]);
356 if (p) {
357 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
358 free(p);
359 }
360 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100361 }
362
363 for (*idx += 1; *(str[*idx]); (*idx)++) {
364 struct pattern_conv_expr *conv_expr;
365
366 end = str[*idx] + strlen(str[*idx]);
367 endw = strchr(str[*idx], '(');
368
369 if (!endw)
370 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200371 else if ((end-1)[0] != ')') {
372 p = my_strndup(str[*idx], endw - str[*idx]);
373 if (p) {
374 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
375 free(p);
376 }
Emeric Brun107ca302010-01-04 16:16:05 +0100377 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200378 }
Emeric Brun107ca302010-01-04 16:16:05 +0100379
380 conv = find_pattern_conv(str[*idx], endw - str[*idx]);
381 if (!conv)
382 break;
383
Willy Tarreau422aa072012-04-20 20:49:27 +0200384 if (conv->in_type >= SMP_TYPES ||
385 conv->out_type >= SMP_TYPES) {
Emeric Brun485479d2010-09-23 18:02:19 +0200386 p = my_strndup(str[*idx], endw - str[*idx]);
387 if (p) {
388 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
389 free(p);
390 }
Emeric Brun107ca302010-01-04 16:16:05 +0100391 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200392 }
Emeric Brun107ca302010-01-04 16:16:05 +0100393
394 /* If impossible type conversion */
Emeric Brun485479d2010-09-23 18:02:19 +0200395 if (!pattern_casts[prev_type][conv->in_type]) {
396 p = my_strndup(str[*idx], endw - str[*idx]);
397 if (p) {
398 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
399 free(p);
400 }
Emeric Brun107ca302010-01-04 16:16:05 +0100401 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200402 }
Emeric Brun107ca302010-01-04 16:16:05 +0100403
404 prev_type = conv->out_type;
405 conv_expr = calloc(1, sizeof(struct pattern_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200406 if (!conv_expr)
407 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100408
409 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
410 conv_expr->conv = conv;
411
412 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200413 char *err_msg = NULL;
414 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200415
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200416 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200417 p = my_strndup(str[*idx], endw - str[*idx]);
418
419 if (p) {
420 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
421 free(p);
422 }
423 goto out_error;
424 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100425
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200426 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 +0200427 p = my_strndup(str[*idx], endw - str[*idx]);
428 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200429 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 +0200430 free(p);
431 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200432 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200433 goto out_error;
434 }
435
436 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
437 p = my_strndup(str[*idx], endw - str[*idx]);
438 if (p) {
439 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
440 free(p);
441 }
442 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200443 goto out_error;
444 }
445 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200446 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200447 p = my_strndup(str[*idx], endw - str[*idx]);
448 if (p) {
449 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100450 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100451 }
Emeric Brun485479d2010-09-23 18:02:19 +0200452 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100453 }
Emeric Brun485479d2010-09-23 18:02:19 +0200454
Emeric Brun107ca302010-01-04 16:16:05 +0100455 }
Emeric Brun485479d2010-09-23 18:02:19 +0200456
Emeric Brun107ca302010-01-04 16:16:05 +0100457 return expr;
458
459out_error:
460 /* TODO: prune_pattern_expr(expr); */
461 return NULL;
462}
463
464/*
465 * Process a fetch + format conversion of defined by the pattern expression <expr>
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200466 * on request or response considering the <opt> parameter.
Emeric Brun107ca302010-01-04 16:16:05 +0100467 * Returns a pointer on a typed pattern structure containing the result or NULL if
468 * pattern is not found or when format conversion failed.
469 * If <p> is not null, function returns results in structure pointed by <p>.
470 * If <p> is null, functions returns a pointer on a static pattern structure.
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200471 *
472 * Note: the fetch functions are required to properly set the return type. The
473 * conversion functions must do so too. However the cast functions do not need
474 * to since they're made to cast mutiple types according to what is required.
Emeric Brun107ca302010-01-04 16:16:05 +0100475 */
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200476struct sample *pattern_process(struct proxy *px, struct session *l4, void *l7,
477 unsigned int opt,
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200478 struct pattern_expr *expr, struct sample *p)
Emeric Brun107ca302010-01-04 16:16:05 +0100479{
480 struct pattern_conv_expr *conv_expr;
481
482 if (p == NULL)
Willy Tarreaub4a88f02012-04-23 21:35:11 +0200483 p = &temp_smp;
Emeric Brun107ca302010-01-04 16:16:05 +0100484
Willy Tarreau342acb42012-04-23 22:03:39 +0200485 p->flags = 0;
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200486 if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100487 return NULL;
488
Emeric Brun107ca302010-01-04 16:16:05 +0100489 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
Willy Tarreau12e50112012-04-25 17:21:49 +0200490 /* we want to ensure that p->type can be casted into
491 * conv_expr->conv->in_type. We have 3 possibilities :
492 * - NULL => not castable.
493 * - c_none => nothing to do (let's optimize it)
494 * - other => apply cast and prepare to fail
495 */
496 if (!pattern_casts[p->type][conv_expr->conv->in_type])
497 return NULL;
498
499 if (pattern_casts[p->type][conv_expr->conv->in_type] != c_none &&
500 !pattern_casts[p->type][conv_expr->conv->in_type](p))
Emeric Brun107ca302010-01-04 16:16:05 +0100501 return NULL;
502
Willy Tarreau12e50112012-04-25 17:21:49 +0200503 /* OK cast succeeded */
504
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200505 /* force the output type after a cast */
Emeric Brun107ca302010-01-04 16:16:05 +0100506 p->type = conv_expr->conv->in_type;
Willy Tarreau342acb42012-04-23 22:03:39 +0200507 if (!conv_expr->conv->process(conv_expr->arg_p, p))
Emeric Brun107ca302010-01-04 16:16:05 +0100508 return NULL;
Emeric Brun107ca302010-01-04 16:16:05 +0100509 }
510 return p;
511}
512
Emeric Brun107ca302010-01-04 16:16:05 +0100513/*****************************************************************/
514/* Pattern format convert functions */
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200515/* These functions set the data type on return. */
Emeric Brun107ca302010-01-04 16:16:05 +0100516/*****************************************************************/
517
Willy Tarreau342acb42012-04-23 22:03:39 +0200518static int pattern_conv_str2lower(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100519{
520 int i;
521
Willy Tarreau342acb42012-04-23 22:03:39 +0200522 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200523 return 0;
524
Willy Tarreau342acb42012-04-23 22:03:39 +0200525 for (i = 0; i < smp->data.str.len; i++) {
526 if ((smp->data.str.str[i] >= 'A') && (smp->data.str.str[i] <= 'Z'))
527 smp->data.str.str[i] += 'a' - 'A';
Emeric Brun107ca302010-01-04 16:16:05 +0100528 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200529 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100530 return 1;
531}
532
Willy Tarreau342acb42012-04-23 22:03:39 +0200533static int pattern_conv_str2upper(const struct arg *arg_p, struct sample *smp)
Emeric Brun107ca302010-01-04 16:16:05 +0100534{
535 int i;
536
Willy Tarreau342acb42012-04-23 22:03:39 +0200537 if (!smp->data.str.size)
Emeric Brun485479d2010-09-23 18:02:19 +0200538 return 0;
539
Willy Tarreau342acb42012-04-23 22:03:39 +0200540 for (i = 0; i < smp->data.str.len; i++) {
541 if ((smp->data.str.str[i] >= 'a') && (smp->data.str.str[i] <= 'z'))
542 smp->data.str.str[i] += 'A' - 'a';
Emeric Brun107ca302010-01-04 16:16:05 +0100543 }
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200544 smp->type = SMP_T_STR;
Emeric Brun107ca302010-01-04 16:16:05 +0100545 return 1;
546}
547
Willy Tarreauf9954102012-04-20 14:03:29 +0200548/* takes the netmask in arg_p */
Willy Tarreau342acb42012-04-23 22:03:39 +0200549static int pattern_conv_ipmask(const struct arg *arg_p, struct sample *smp)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100550{
Willy Tarreau342acb42012-04-23 22:03:39 +0200551 smp->data.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaub8c8f1f2012-04-23 22:38:26 +0200552 smp->type = SMP_T_IPV4;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100553 return 1;
554}
555
Emeric Brun107ca302010-01-04 16:16:05 +0100556/* Note: must not be declared <const> as its list will be overwritten */
557static struct pattern_conv_kw_list pattern_conv_kws = {{ },{
Willy Tarreau422aa072012-04-20 20:49:27 +0200558 { "upper", pattern_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR },
559 { "lower", pattern_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR },
560 { "ipmask", pattern_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200561 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100562}};
563
564__attribute__((constructor))
565static void __pattern_init(void)
566{
567 /* register pattern format convert keywords */
568 pattern_register_convs(&pattern_conv_kws);
569}