blob: a31bcda5d601ea4b698e5506b3918e11a977a1b4 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Regex and string management functions.
3 *
Willy Tarreauf4f04122010-01-28 18:10:50 +01004 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
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 <ctype.h>
14#include <stdlib.h>
15#include <string.h>
16
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020017#include <common/config.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020018#include <common/regex.h>
19#include <common/standard.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020020#include <proto/log.h>
21
22/* regex trash buffer used by various regex tests */
23regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
24
Willy Tarreauc8746532014-05-28 23:05:07 +020025int exp_replace(char *dst, unsigned int dst_size, char *src, const char *str, const regmatch_t *matches)
Willy Tarreaubaaee002006-06-26 02:48:02 +020026{
27 char *old_dst = dst;
Sasha Pachevc6002042014-05-26 12:33:48 -060028 char* dst_end = dst + dst_size;
Willy Tarreaubaaee002006-06-26 02:48:02 +020029
30 while (*str) {
31 if (*str == '\\') {
32 str++;
Sasha Pachevc6002042014-05-26 12:33:48 -060033 if (!*str)
34 return -1;
35
Willy Tarreau8f8e6452007-06-17 21:51:38 +020036 if (isdigit((unsigned char)*str)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +020037 int len, num;
38
39 num = *str - '0';
40 str++;
41
42 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
43 len = matches[num].rm_eo - matches[num].rm_so;
Sasha Pachevc6002042014-05-26 12:33:48 -060044
45 if (dst + len >= dst_end)
46 return -1;
47
Willy Tarreaubaaee002006-06-26 02:48:02 +020048 memcpy(dst, src + matches[num].rm_so, len);
49 dst += len;
50 }
51
52 } else if (*str == 'x') {
53 unsigned char hex1, hex2;
54 str++;
55
Sasha Pachevc6002042014-05-26 12:33:48 -060056 if (!*str)
57 return -1;
58
Willy Tarreaubaaee002006-06-26 02:48:02 +020059 hex1 = toupper(*str++) - '0';
Sasha Pachevc6002042014-05-26 12:33:48 -060060
61 if (!*str)
62 return -1;
63
Willy Tarreaubaaee002006-06-26 02:48:02 +020064 hex2 = toupper(*str++) - '0';
65
66 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
67 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
Sasha Pachevc6002042014-05-26 12:33:48 -060068
69 if (dst >= dst_end)
70 return -1;
71
Willy Tarreaubaaee002006-06-26 02:48:02 +020072 *dst++ = (hex1<<4) + hex2;
73 } else {
Sasha Pachevc6002042014-05-26 12:33:48 -060074 if (dst >= dst_end)
75 return -1;
76
Willy Tarreaubaaee002006-06-26 02:48:02 +020077 *dst++ = *str++;
78 }
79 } else {
Sasha Pachevc6002042014-05-26 12:33:48 -060080 if (dst >= dst_end)
81 return -1;
82
Willy Tarreaubaaee002006-06-26 02:48:02 +020083 *dst++ = *str++;
84 }
85 }
Sasha Pachevc6002042014-05-26 12:33:48 -060086 if (dst >= dst_end)
87 return -1;
88
Willy Tarreaubaaee002006-06-26 02:48:02 +020089 *dst = '\0';
90 return dst - old_dst;
91}
92
93/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
Willy Tarreaub17916e2006-10-15 15:17:57 +020094const char *check_replace_string(const char *str)
Willy Tarreaubaaee002006-06-26 02:48:02 +020095{
Willy Tarreaub17916e2006-10-15 15:17:57 +020096 const char *err = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +020097 while (*str) {
98 if (*str == '\\') {
99 err = str; /* in case of a backslash, we return the pointer to it */
100 str++;
101 if (!*str)
102 return err;
Willy Tarreau8f8e6452007-06-17 21:51:38 +0200103 else if (isdigit((unsigned char)*str))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200104 err = NULL;
105 else if (*str == 'x') {
106 str++;
107 if (!ishex(*str))
108 return err;
109 str++;
110 if (!ishex(*str))
111 return err;
112 err = NULL;
113 }
114 else {
115 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
116 err = NULL;
117 }
118 }
119 str++;
120 }
121 return err;
122}
123
124
125/* returns the pointer to an error in the replacement string, or NULL if OK */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200126const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
Willy Tarreauf4f04122010-01-28 18:10:50 +0100127 int action, const char *replace, void *cond)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200128{
129 struct hdr_exp *exp;
130
131 if (replace != NULL) {
Willy Tarreaub17916e2006-10-15 15:17:57 +0200132 const char *err;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200133 err = check_replace_string(replace);
134 if (err)
135 return err;
136 }
137
138 while (*head != NULL)
139 head = &(*head)->next;
140
141 exp = calloc(1, sizeof(struct hdr_exp));
142
143 exp->preg = preg;
144 exp->replace = replace;
145 exp->action = action;
Willy Tarreauf4f04122010-01-28 18:10:50 +0100146 exp->cond = cond;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200147 *head = exp;
148
149 return NULL;
150}
151
Thierry FOURNIER799c0422013-12-06 20:36:20 +0100152int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err)
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200153{
154#ifdef USE_PCRE_JIT
155 int flags = 0;
156 const char *error;
157 int erroffset;
158
159 if (!cs)
160 flags |= PCRE_CASELESS;
161 if (!cap)
162 flags |= PCRE_NO_AUTO_CAPTURE;
163
164 regex->reg = pcre_compile(str, flags, &error, &erroffset, NULL);
165 if (!regex->reg) {
166 memprintf(err, "regex '%s' is invalid (error=%s, erroffset=%d)", str, error, erroffset);
167 return 0;
168 }
169
170 regex->extra = pcre_study(regex->reg, PCRE_STUDY_JIT_COMPILE, &error);
171 if (!regex->extra) {
172 pcre_free(regex->reg);
173 memprintf(err, "failed to compile regex '%s' (error=%s)", str, error);
174 return 0;
175 }
176#else
177 int flags = REG_EXTENDED;
178
179 if (!cs)
180 flags |= REG_ICASE;
181 if (!cap)
182 flags |= REG_NOSUB;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200183
Thierry FOURNIER799c0422013-12-06 20:36:20 +0100184 if (regcomp(&regex->regex, str, flags) != 0) {
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200185 memprintf(err, "regex '%s' is invalid", str);
186 return 0;
187 }
188#endif
189 return 1;
190}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200191
192/*
193 * Local variables:
194 * c-indent-level: 8
195 * c-basic-offset: 8
196 * End:
197 */