diff --git a/include/proto/acl.h b/include/proto/acl.h index 86cbe74ff..ace72dd90 100644 --- a/include/proto/acl.h +++ b/include/proto/acl.h @@ -118,6 +118,9 @@ int acl_parse_range(const char *text, struct acl_pattern *pattern); /* Parse a string. It is allocated and duplicated. */ int acl_parse_str(const char *text, struct acl_pattern *pattern); +/* Parse a regex. It is allocated. */ +int acl_parse_reg(const char *text, struct acl_pattern *pattern); + /* Parse an IP address and an optional mask in the form addr[/mask]. * The addr may either be an IPv4 address or a hostname. The mask * may either be a dotted mask or a number of bits. Returns 1 if OK, @@ -149,6 +152,13 @@ int acl_match_dom(struct acl_test *test, struct acl_pattern *pattern); /* Check that the IPv4 address in matches the IP/mask in pattern */ int acl_match_ip(struct acl_test *test, struct acl_pattern *pattern); +/* Executes a regex. It needs to change the data. If it is marked READ_ONLY + * then it will be allocated and duplicated in place so that others may use + * it later on. Note that this is embarrassing because we always try to avoid + * allocating memory at run time. + */ +int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern); + #endif /* _PROTO_ACL_H */ /* diff --git a/src/acl.c b/src/acl.c index e5d7594ea..1dce3ea3f 100644 --- a/src/acl.c +++ b/src/acl.c @@ -47,6 +47,44 @@ int acl_match_str(struct acl_test *test, struct acl_pattern *pattern) return 0; } +/* Executes a regex. It needs to change the data. If it is marked READ_ONLY + * then it will be allocated and duplicated in place so that others may use + * it later on. Note that this is embarrassing because we always try to avoid + * allocating memory at run time. + */ +int acl_match_reg(struct acl_test *test, struct acl_pattern *pattern) +{ + char old_char; + int ret; + + if (unlikely(test->flags & ACL_TEST_F_READ_ONLY)) { + char *new_str; + + new_str = calloc(1, test->len + 1); + if (!new_str) + return 0; + + memcpy(new_str, test->ptr, test->len); + new_str[test->len] = 0; + if (test->flags & ACL_TEST_F_MUST_FREE) + free(test->ptr); + test->ptr = new_str; + test->flags |= ACL_TEST_F_MUST_FREE; + test->flags &= ~ACL_TEST_F_READ_ONLY; + } + + old_char = test->ptr[test->len]; + test->ptr[test->len] = 0; + + if (regexec(pattern->ptr.reg, test->ptr, 0, NULL, 0) == 0) + ret = 1; + else + ret = 0; + + test->ptr[test->len] = old_char; + return ret; +} + /* Checks that the pattern matches the beginning of the tested string. */ int acl_match_beg(struct acl_test *test, struct acl_pattern *pattern) { @@ -199,6 +237,25 @@ int acl_parse_str(const char *text, struct acl_pattern *pattern) return 1; } +/* Parse a regex. It is allocated. */ +int acl_parse_reg(const char *text, struct acl_pattern *pattern) +{ + regex_t *preg; + + preg = calloc(1, sizeof(regex_t)); + + if (!preg) + return 0; + + if (regcomp(preg, text, REG_EXTENDED | REG_NOSUB) != 0) { + free(preg); + return 0; + } + + pattern->ptr.reg = preg; + return 1; +} + /* Parse an integer. It is put both in min and max. */ int acl_parse_int(const char *text, struct acl_pattern *pattern) { diff --git a/src/proto_http.c b/src/proto_http.c index 6d4c15280..9506b167e 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -5276,7 +5276,8 @@ static int acl_fetch_url(struct proxy *px, struct session *l4, void *l7, void *a test->len = txn->req.sl.rq.u_l; test->ptr = txn->req.sol + txn->req.sl.rq.u; - test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST; + /* we do not need to set READ_ONLY because the data is in a buffer */ + test->flags = ACL_TEST_F_VOL_1ST; return 1; } @@ -5299,10 +5300,11 @@ static struct acl_kw_list acl_kws = {{ },{ { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub }, { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir }, { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom }, - { NULL, NULL, NULL, NULL }, -#if 0 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg }, + { NULL, NULL, NULL, NULL }, + +#if 0 { "line", acl_parse_str, acl_fetch_line, acl_match_str }, { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg }, { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },