summaryrefslogtreecommitdiffabout
path: root/src/vmod_dbrw.c
Side-by-side diff
Diffstat (limited to 'src/vmod_dbrw.c') (more/less context) (ignore whitespace changes)
-rw-r--r--src/vmod_dbrw.c110
1 files changed, 67 insertions, 43 deletions
diff --git a/src/vmod_dbrw.c b/src/vmod_dbrw.c
index 63d4ea1..beeb9af 100644
--- a/src/vmod_dbrw.c
+++ b/src/vmod_dbrw.c
@@ -1,8 +1,8 @@
/* This file is part of vmod-dbrw
- Copyright (C) 2013-2018 Sergey Poznyakoff
+ Copyright (C) 2013-2019 Sergey Poznyakoff
Vmod-dbrw is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -22,12 +22,17 @@
enum {
QDISP_NONE,
QDISP_APPEND,
QDISP_DISCARD
};
+enum {
+ MATCH_REGEX,
+ MATCH_EQ
+};
+
void
dbrw_debug(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(LOG_DAEMON|LOG_DEBUG, fmt, ap);
@@ -151,13 +156,13 @@ is_http_status(const char *arg)
return '1' <= arg[0] && arg[0] <= '5' &&
'0' <= arg[1] && arg[1] <= '9' &&
'0' <= arg[2] && arg[2] <= '9';
}
static int
-parse_flags(const char *arg, int *qdisp, int *flags, char status[])
+parse_flags(const char *arg, int *qdisp, int *flags, int *match, char status[])
{
struct wordsplit ws;
int rc = 0;
int i;
if (!arg)
@@ -201,12 +206,16 @@ parse_flags(const char *arg, int *qdisp, int *flags, char status[])
rc = 1;
} else {
strncpy(status, ws.ws_wordv[i] + 2,
HTTP_STATUS_LEN);
status[HTTP_STATUS_LEN] = 0;
}
+ } else if (strcmp(ws.ws_wordv[i], "regex") == 0) {
+ *match = MATCH_REGEX;
+ } else if (strcmp(ws.ws_wordv[i], "eq") == 0) {
+ *match = MATCH_EQ;
} else {
dbrw_error("unrecognized flag: %s", ws.ws_wordv[i]);
rc = 1;
}
}
@@ -274,19 +283,21 @@ vmod_config(VRT_CTX, struct vmod_priv *priv,
conf->idle_timeout = atoi(s);
else
conf->idle_timeout = -2;
conf->qdisp = QDISP_NONE;
conf->regflags = REG_EXTENDED;
+ conf->match_type = MATCH_REGEX;
conf->status[0] = 0;
s = findparam(conf->param, "flags");
if (s)
parse_flags(s,
&conf->qdisp,
&conf->regflags,
+ &conf->match_type,
conf->status);
AZ(pthread_mutex_lock(&config_pool_mtx));
VTAILQ_INSERT_HEAD(&config_pool, conf, list);
pthread_mutex_unlock(&config_pool_mtx);
}
@@ -410,12 +421,13 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
regex_t re;
int rc;
size_t matchcount; /* Number of used entries in matches */
int rflags = conn->conf->regflags;
char status[HTTP_STATUS_LEN+1];
int qdisp = conn->conf->qdisp;
+ int match_type = conn->conf->match_type;
char *qry = NULL;
if (ISEMPTY(pat)) {
res = WS_Copy(WSPTR(ctx), sql_get_column(conn, i, 0), -1);
break;
}
@@ -432,13 +444,13 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
debug(conn->conf, 1, ("expanded to \"%s\" ~ \"%s\"",
pat, val));
strcpy(status, conn->conf->status);
if (nf == 4) {
if (parse_flags(sql_get_column(conn, i, 3),
- &qdisp, &rflags, status))
+ &qdisp, &rflags, &match_type, status))
continue;
}
switch (qdisp) {
case QDISP_NONE:
break;
@@ -453,44 +465,51 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
debug(conn->conf, 1,
("discarding query part \"%s\"", qry));
*qry = 0;
qry = NULL;
}
}
-
- rc = regcomp(&re, pat, rflags);
- if (rc) {
- char errbuf[512];
-
- regerror(rc, &re, errbuf, sizeof(errbuf));
- dbrw_error("cannot compile regexp \"%s\": %s",
- pat, errbuf);
- continue;
- }
- matchcount = re.re_nsub + 1;
- if (conn->matchsize < matchcount) {
- void *p = realloc(conn->matches,
- sizeof(conn->matches[0]) * matchcount);
- if (!p) {
- dbrw_error("not enough memory");
- regfree(&re);
+ if (match_type == MATCH_EQ) {
+ rc = ((rflags & REG_ICASE)
+ ? strcasecmp : strcmp) (pat, val);
+ } else {
+ rc = regcomp(&re, pat, rflags);
+ if (rc) {
+ char errbuf[512];
+
+ regerror(rc, &re, errbuf, sizeof(errbuf));
+ dbrw_error("cannot compile regexp \"%s\": %s",
+ pat, errbuf);
continue;
}
- conn->matches = p;
- conn->matchsize = matchcount;
- }
- rc = regexec(&re, val, matchcount, conn->matches, 0);
+ matchcount = re.re_nsub + 1;
+ if (conn->matchsize < matchcount) {
+ void *p = realloc(conn->matches,
+ sizeof(conn->matches[0]) * matchcount);
+ if (!p) {
+ dbrw_error("not enough memory");
+ regfree(&re);
+ continue;
+ }
+ conn->matches = p;
+ conn->matchsize = matchcount;
+ }
+
+ rc = regexec(&re, val, matchcount, conn->matches, 0);
- if (rc == 0)
- res = expand_backref(ctx, val,
- sql_get_column(conn, i, 0),
- matchcount, conn->matches, qry);
+ if (rc == 0)
+ res = expand_backref(ctx, val,
+ sql_get_column(conn, i, 0),
+ matchcount,
+ conn->matches, qry);
- regfree(&re);
+ regfree(&re);
+ }
+
if (rc == 0) {
debug(conn->conf, 1, ("match"));
if (status[0]) {
debug(conn->conf, 1,
("setting status %s", status));
dbrw_sethdr(ctx, HDR_REQ,
@@ -603,39 +622,40 @@ query_command_expand(char **ret, const char *cmd, size_t len, char **argv,
return ec->exp(clos, argv, ret);
}
return expand_error(ret, argv[0], "unknown command");
}
-static char *
-do_rewrite(VRT_CTX, struct dbrw_connection *cp, VCL_STRING arg)
+static int
+do_rewrite(VRT_CTX, struct dbrw_connection *cp, VCL_STRING arg, char **result)
{
struct wordsplit ws, wsenv;
int i, rc;
- char *res;
int wsflags;
+
+ *result = NULL;
if (sql_connect(cp) || cp->state != state_connected)
- return NULL;
+ return -1;
debug(cp->conf, 2, ("vmod_rewrite: splitting arg"));
wsenv.ws_delim = ";";
if (wordsplit(arg, &wsenv, WRDSF_NOVAR|WRDSF_NOCMD|WRDSF_DELIM)) {
dbrw_error("cannot split string `%s': %s",
arg, wordsplit_strerror(&wsenv));
- return NULL;
+ return -1;
}
if (cp->conf->backend->sql_escape) {
debug(cp->conf, 2, ("escaping variables"));
for (i = 0; i < wsenv.ws_wordc; i++) {
char *p = sql_escape(cp, wsenv.ws_wordv[i]);
if (!p) {
dbrw_error("cannot expand argument");
wordsplit_free(&wsenv);
- return NULL;
+ return -1;
}
free(wsenv.ws_wordv[i]);
wsenv.ws_wordv[i] = p;
debug(cp->conf, 3, ("%d: %s",i,p));
}
}
@@ -654,42 +674,46 @@ do_rewrite(VRT_CTX, struct dbrw_connection *cp, VCL_STRING arg)
rc = wordsplit(cp->conf->query, &ws, wsflags);
if (rc) {
dbrw_error("cannot expand query `%s': %s",
cp->conf->query, wordsplit_strerror(&ws));
wordsplit_free(&wsenv);
- return NULL;
+ return -1;
}
rc = sql_query(cp, ws.ws_wordv[0]);
wordsplit_free(&ws);
if (rc) {
- debug(cp->conf, 1, ("vmod_rewrite: query failed"));
+ dbrw_error("vmod_rewrite: query failed");
wordsplit_free(&wsenv);
- return NULL;
+ return -1;
}
- res = findmatch(ctx, cp, wsenv.ws_wordv);
+ *result = findmatch(ctx, cp, wsenv.ws_wordv);
wordsplit_free(&wsenv);
sql_free_result(cp);
- return res;
+ return 0;
}
VCL_STRING
vmod_rewrite(VRT_CTX, struct vmod_priv *priv, VCL_STRING arg)
{
struct dbrw_config *conf = priv->priv;
struct dbrw_connection *cp;
char *res = NULL;
-
+ int rc;
+
AN(conf);
debug(conf, 2, ("vmod_rewrite(%s) begin", arg));
cp = dbrw_connection_get(conf);
AN(cp);
- res = do_rewrite(ctx, cp, arg);
+ rc = do_rewrite(ctx, cp, arg, &res);
dbrw_connection_release(cp);
- debug(conf, 1, ("vmod_rewrite: res=%s", res ? res : "(NULL)"));
+ debug(conf, 1, ("vmod_rewrite: %d, res=%s", rc, res ? res : "(NULL)"));
+ if (rc) {
+ dbrw_sethdr(ctx, HDR_REQ, "\022X-VMOD-DBRW-Error:", "1");
+ }
return res;
}

Return to:

Send suggestions and report system problems to the System administrator.