summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-02-13 12:42:26 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-02-13 12:49:44 (GMT)
commit49ab7b5fa7843a77605b91adf8a3689794fc091a (patch) (unidiff)
treea66112caaaf9fe883ce449c788df1a8480594db9
parent7eb61c964c74af1bafb948584c0404208c9467b8 (diff)
downloadvmod-dbrw-49ab7b5fa7843a77605b91adf8a3689794fc091a.tar.gz
vmod-dbrw-49ab7b5fa7843a77605b91adf8a3689794fc091a.tar.bz2
Implement two new flags and a special req.http header to indicate errors
* NEWS: Document changes. * doc/vmod-dbrw.3: Likewise. * doc/vmod-dbrw.texi: Likewise. * configure.ac: Version 2.4.90 * src/dbrw.h (dbrw_config): New member: match_type * src/vmod_dbrw.c (parse_flags): Handle "eq" and "regex" flags. (findmatch): Handle the "eq" flag. (do_rewrite): Return error code. (vmod_rewrite): Set the X-VMOD-DBRW-Error header on errors. * tests/atlocal.in (at_vcl_backend): Special handling for X-VMOD-DBRW-Error. * tests/initdb.at: Test the 'eq' flag. * tests/rewrite07.at: New testcase. * tests/Makefile.am: Add new testcase. * tests/testsuite.at: Likewise.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS19
-rw-r--r--configure.ac4
-rw-r--r--doc/vmod-dbrw.324
-rw-r--r--doc/vmod-dbrw.texi38
-rw-r--r--src/dbrw.h1
-rw-r--r--src/vmod_dbrw.c110
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/atlocal.in9
-rw-r--r--tests/initdb.at4
-rw-r--r--tests/rewrite07.at40
-rw-r--r--tests/testsuite.at1
11 files changed, 198 insertions, 53 deletions
diff --git a/NEWS b/NEWS
index 0300ec3..516ca69 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,26 @@
1vmod-dbrw -- history of user-visible changes. 2018-12-10 1vmod-dbrw -- history of user-visible changes. 2019-02-13
2See the end of file for copying conditions. 2See the end of file for copying conditions.
3 3
4Please send vmod-dbrw bug reports to <gray@gnu.org> 4Please send vmod-dbrw bug reports to <gray@gnu.org>
5 5
6Version 2.4.90 (git)
7
8* req.http.X-VMOD-DBRW-Error
9
10This header is set to 1 by dbrw.rewrite to indicate that an error
11occurred during the rewrite.
12
13* New flags: regex and eq
14
15One of this flags can appear in the fourth column of the returned data
16set. The 'eq' flag instructs dbrw.rewrite to use exact string match,
17instead of regular expressions. The 'regex' flag instructs it to use
18regular expression matching. It is the default.
19
20
6Version 2.4, 2018-12-10 21Version 2.4, 2018-12-10
7 22
8* Support for Varnish version 6.0.2 23* Support for Varnish version 6.0.2
9 24
10 25
11Version 2.3, 2018-12-08 26Version 2.3, 2018-12-08
@@ -75,13 +90,13 @@ Version 1.0, 2013-07-20
75 90
76Initial release 91Initial release
77 92
78========================================================================= 93=========================================================================
79Copyright information: 94Copyright information:
80 95
81Copyright (C) 2013-2018 Sergey Poznyakoff 96Copyright (C) 2013-2019 Sergey Poznyakoff
82 97
83 Permission is granted to anyone to make or distribute verbatim copies 98 Permission is granted to anyone to make or distribute verbatim copies
84 of this document as received, in any medium, provided that the 99 of this document as received, in any medium, provided that the
85 copyright notice and this permission notice are preserved, 100 copyright notice and this permission notice are preserved,
86 thus giving the recipient permission to redistribute in turn. 101 thus giving the recipient permission to redistribute in turn.
87 102
diff --git a/configure.ac b/configure.ac
index 62c3afe..fd618d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
1# This file is part of vmod-dbrw -*- autoconf -*- 1# This file is part of vmod-dbrw -*- autoconf -*-
2# Copyright (C) 2013-2018 Sergey Poznyakoff 2# Copyright (C) 2013-2019 Sergey Poznyakoff
3# 3#
4# Vmod-dbrw is free software; you can redistribute it and/or modify 4# Vmod-dbrw is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option) 6# the Free Software Foundation; either version 3, or (at your option)
7# any later version. 7# any later version.
8# 8#
@@ -11,13 +11,13 @@
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details. 12# GNU General Public License for more details.
13# 13#
14# You should have received a copy of the GNU General Public License 14# You should have received a copy of the GNU General Public License
15# along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>. 15# along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
16AC_PREREQ(2.69) 16AC_PREREQ(2.69)
17AC_INIT([vmod-dbrw], 2.4, [gray@gnu.org]) 17AC_INIT([vmod-dbrw], 2.4.90, [gray@gnu.org])
18AC_CONFIG_AUX_DIR([build-aux]) 18AC_CONFIG_AUX_DIR([build-aux])
19AC_CONFIG_MACRO_DIR([m4]) 19AC_CONFIG_MACRO_DIR([m4])
20AC_CONFIG_SRCDIR(src/vmod_dbrw.vcc) 20AC_CONFIG_SRCDIR(src/vmod_dbrw.vcc)
21AM_CONFIG_HEADER(config.h) 21AM_CONFIG_HEADER(config.h)
22 22
23AC_SUBST([AC_VMOD_BASENAME],[dbrw]) 23AC_SUBST([AC_VMOD_BASENAME],[dbrw])
diff --git a/doc/vmod-dbrw.3 b/doc/vmod-dbrw.3
index 2abef65..9bec008 100644
--- a/doc/vmod-dbrw.3
+++ b/doc/vmod-dbrw.3
@@ -10,13 +10,13 @@
10.\" but WITHOUT ANY WARRANTY; without even the implied warranty of 10.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
11.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12.\" GNU General Public License for more details. 12.\" GNU General Public License for more details.
13.\" 13.\"
14.\" You should have received a copy of the GNU General Public License 14.\" You should have received a copy of the GNU General Public License
15.\" along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>. 15.\" along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
16.TH VMOD-DBRW 3 "December 8, 2018" "VMOD-DBRW" "User Reference" 16.TH VMOD-DBRW 3 "February 13, 2019" "VMOD-DBRW" "User Reference"
17.SH NAME 17.SH NAME
18vmod-dbrw \- Database-driven rewrite rules for Varnish Cache 18vmod-dbrw \- Database-driven rewrite rules for Varnish Cache
19.SH SYNOPSIS 19.SH SYNOPSIS
20.B import dbrw; 20.B import dbrw;
21.PP 21.PP
22.BI "VOID dbrw.config(STRING " dbtype ", STRING " params ", STRING " query ");" 22.BI "VOID dbrw.config(STRING " dbtype ", STRING " params ", STRING " query ");"
@@ -187,29 +187,49 @@ modify regular expression handling. The following flags are defined:
187.BR NC " or " nocase 187.BR NC " or " nocase
188Treat \fBregexp\fR as case-insensitive. 188Treat \fBregexp\fR as case-insensitive.
189.TP 189.TP
190.B case 190.B case
191Treat \fBregexp\fR as case-sensitive (default). 191Treat \fBregexp\fR as case-sensitive (default).
192.TP 192.TP
193.B eq
194Use exact string matching.
195.TP
193.BR QSA " or " qsappend 196.BR QSA " or " qsappend
194Treat the resulting value as URL; append any query string from the 197Treat the resulting value as URL; append any query string from the
195original \fBvalue\fR to it. 198original \fBvalue\fR to it.
196.TP 199.TP
197.BR QSD " or " qsdiscard 200.BR QSD " or " qsdiscard
198Treat the resulting value as URL; discard any query string attached to 201Treat the resulting value as URL; discard any query string attached to
199the original \fBvalue\fR. 202the original \fBvalue\fR.
200.TP 203.TP
201\fBredirect=\fICODE\fR or \fBR=\fICODE\fR 204\fBredirect=\fICODE\fR or \fBR=\fICODE\fR
202On success, set the \fBX\-VMOD\-DBRW\-Status\fR header to \fICODE\fR, 205On success, set the \fBX\-VMOD\-DBRW\-Status\fR header to \fICODE\fR,
203which must be a valid HTTP status code. 206which must be a valid HTTP status code.
207.TP
208.B regex
209Use regular expression matching. This is the default. This flag is
210provided for completeness sake, as a counterpart of
211.BR eq .
204.PP 212.PP
205If \fBregexp\fR or \fBvalue\fR is NULL, the tuple is handled as 213If \fBregexp\fR or \fBvalue\fR is NULL, the tuple is handled as
206described in 214described in
207.BR "Strict matches" . 215.BR "Strict matches" .
208.PP 216.PP
209If \fBflags\fR is NULL, it is ignored. 217If \fBflags\fR is NULL, it is ignored.
218.SH HTTP HEADERS
219Upon return,
220.B dbrw.return
221may set one of the following headers in
222.BR resp.http :
223.TP
224.B X\-VMOD\-DBRW\-Status
225If the \fBredirect\fR flag was used, this header contains the HTTP
226response code to be used instead of the default.
227.TP
228.B X\-VMOD\-DBRW\-Error
229This header is set to \fB1\fR if an error occurred during the rewrite.
210.SH EXAMPLES 230.SH EXAMPLES
211The examples in this section assume \fBMySQL\fR databases. Any 231The examples in this section assume \fBMySQL\fR databases. Any
212details not related to \fBvmod-dbrw\fR are omitted. 232details not related to \fBvmod-dbrw\fR are omitted.
213.SS Redirects 233.SS Redirects
214.PP 234.PP
215This example shows how to implement apache-style permanent redirects 235This example shows how to implement apache-style permanent redirects
diff --git a/doc/vmod-dbrw.texi b/doc/vmod-dbrw.texi
index 734dadb..6a987ed 100644
--- a/doc/vmod-dbrw.texi
+++ b/doc/vmod-dbrw.texi
@@ -129,13 +129,20 @@ This latter form can be used in contexts where the variable reference is
129immediately followed by a letter, digit or underscore, to prevent it 129immediately followed by a letter, digit or underscore, to prevent it
130from being counted as a part of the name. Special syntax is available 130from being counted as a part of the name. Special syntax is available
131for substituting default values and invoking built-in functions during 131for substituting default values and invoking built-in functions during
132the expansion of the query. @xref{Expansions}, for a detailed 132the expansion of the query. @xref{Expansions}, for a detailed
133description of these. 133description of these.
134 134
135@anchor{X-VMOD-DBRW-Error}
136@vindex X-VMOD-DBRW-Error
135Having undergone expansions, the query is sent to the database server. 137Having undergone expansions, the query is sent to the database server.
138If the query returns no records or if an error occured, @code{rewrite}
139returns empty string. In case of error, it also sets the HTTP header
140@samp{X-VMOD-DBRW-Error: 1}. It can be used in VLC code to provide a
141special handling for such failures.
142
136The returned set of records (if non-empty) is processed depending on the 143The returned set of records (if non-empty) is processed depending on the
137number of fields it contains. 144number of fields it contains.
138 145
139@cindex result interpretation 146@cindex result interpretation
140@anchor{result interpretation} 147@anchor{result interpretation}
141@cindex strict matching 148@cindex strict matching
@@ -163,13 +170,13 @@ subexpression in @var{regexp}. For compatibility with the traditional
163usage, the @code{\@var{digit}} notation is also allowed. The 170usage, the @code{\@var{digit}} notation is also allowed. The
164resulting value is then returned to the caller. 171resulting value is then returned to the caller.
165 172
166@cindex flags 173@cindex flags
167@anchor{flags} 174@anchor{flags}
168Optional @var{flags} column is a comma-separated list of flags that 175Optional @var{flags} column is a comma-separated list of flags that
169modify regular expression handling: 176control the matching algorithm.
170 177
171@table @samp 178@table @samp
172@kindex NC 179@kindex NC
173@kindex nocase 180@kindex nocase
174@cindex regular expression, case-insensitive 181@cindex regular expression, case-insensitive
175@cindex case-insensitive regular expression 182@cindex case-insensitive regular expression
@@ -180,12 +187,17 @@ Treat @var{regexp} as case-insensitive regular expression.
180@kindex case 187@kindex case
181@cindex regular expression, case-sensitive 188@cindex regular expression, case-sensitive
182@cindex case-sensitive regular expression 189@cindex case-sensitive regular expression
183@item case 190@item case
184Treat @var{regexp} as case-sensitive (default). 191Treat @var{regexp} as case-sensitive (default).
185 192
193@kindex eq
194@cindex exact matching
195@item eq
196Use exact string matching.
197
186@kindex QSA 198@kindex QSA
187@kindex qsappend 199@kindex qsappend
188@cindex query string handling 200@cindex query string handling
189@cindex append query string 201@cindex append query string
190@item QSA 202@item QSA
191@itemx qsappend 203@itemx qsappend
@@ -206,12 +218,18 @@ the original @var{value}.
206@cindex redirection code 218@cindex redirection code
207@cindex status code 219@cindex status code
208@item redirect=@var{code} 220@item redirect=@var{code}
209@item R=@var{code} 221@item R=@var{code}
210On success, set the @samp{X-VMOD-DBRW-Status} header to @var{code}, 222On success, set the @samp{X-VMOD-DBRW-Status} header to @var{code},
211which must be a valid HTTP status code. 223which must be a valid HTTP status code.
224
225@kindex regex
226@cindex regular expression matching
227@item regex
228Use regular expression matching. This is the default. This flag is
229provided for completeness sake, as a counterpart of @samp{eq}.
212@end table 230@end table
213 231
214If @var{regexp} or @var{value} is NULL, strict matching is assumed 232If @var{regexp} or @var{value} is NULL, strict matching is assumed
215(@pxref{strict matching}). 233(@pxref{strict matching}).
216 234
217If @var{flags} is NULL, it is ignored. 235If @var{flags} is NULL, it is ignored.
@@ -698,12 +716,30 @@ sub vcl_synth @{
698@end example 716@end example
699 717
700The @code{X-VMOD-DBRW-Status} header, if set, contains the status code to be 718The @code{X-VMOD-DBRW-Status} header, if set, contains the status code to be
701returned to the client (@pxref{X-VMOD-DBRW-Status}). Notice the use 719returned to the client (@pxref{X-VMOD-DBRW-Status}). Notice the use
702of the @command{vmod_std} module to cast it to integer. 720of the @command{vmod_std} module to cast it to integer.
703 721
722If an error occured during the rewrite, it is recommended to not
723cache the response. This way the next request will call rewrite again
724and eventually complete the rewriting. This can be achieved using the
725following @code{vcl_backend_response} fragment:
726
727@example
728@group
729sub vcl_backend_response
730@{
731 if (bereq.http.X-VMOD-DBRW-Error == "1") @{
732 set beresp.uncacheable = true;
733 return (deliver);
734 @}
735@}
736@end group
737@end example
738
739
704@node Reporting Bugs 740@node Reporting Bugs
705@chapter How to Report a Bug 741@chapter How to Report a Bug
706 742
707 Email bug reports to @email{gray@@gnu.org}. 743 Email bug reports to @email{gray@@gnu.org}.
708 744
709 As the purpose of bug reporting is to improve software, please be 745 As the purpose of bug reporting is to improve software, please be
diff --git a/src/dbrw.h b/src/dbrw.h
index bd0aa2a..9a8adf6 100644
--- a/src/dbrw.h
+++ b/src/dbrw.h
@@ -68,12 +68,13 @@ struct dbrw_config {
68 struct dbrw_backend *backend; 68 struct dbrw_backend *backend;
69 char **param; 69 char **param;
70 char *param_str; 70 char *param_str;
71 char *query; 71 char *query;
72 int qdisp; 72 int qdisp;
73 int regflags; 73 int regflags;
74 int match_type;
74 char status[HTTP_STATUS_LEN+1]; 75 char status[HTTP_STATUS_LEN+1];
75 int idle_timeout; 76 int idle_timeout;
76 VTAILQ_ENTRY(dbrw_config) list; 77 VTAILQ_ENTRY(dbrw_config) list;
77}; 78};
78 79
79struct dbrw_connection { 80struct dbrw_connection {
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 @@
1/* This file is part of vmod-dbrw 1/* This file is part of vmod-dbrw
2 Copyright (C) 2013-2018 Sergey Poznyakoff 2 Copyright (C) 2013-2019 Sergey Poznyakoff
3 3
4 Vmod-dbrw is free software; you can redistribute it and/or modify 4 Vmod-dbrw is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
@@ -22,12 +22,17 @@
22enum { 22enum {
23 QDISP_NONE, 23 QDISP_NONE,
24 QDISP_APPEND, 24 QDISP_APPEND,
25 QDISP_DISCARD 25 QDISP_DISCARD
26}; 26};
27 27
28enum {
29 MATCH_REGEX,
30 MATCH_EQ
31};
32
28void 33void
29dbrw_debug(const char *fmt, ...) 34dbrw_debug(const char *fmt, ...)
30{ 35{
31 va_list ap; 36 va_list ap;
32 va_start(ap, fmt); 37 va_start(ap, fmt);
33 vsyslog(LOG_DAEMON|LOG_DEBUG, fmt, ap); 38 vsyslog(LOG_DAEMON|LOG_DEBUG, fmt, ap);
@@ -151,13 +156,13 @@ is_http_status(const char *arg)
151 return '1' <= arg[0] && arg[0] <= '5' && 156 return '1' <= arg[0] && arg[0] <= '5' &&
152 '0' <= arg[1] && arg[1] <= '9' && 157 '0' <= arg[1] && arg[1] <= '9' &&
153 '0' <= arg[2] && arg[2] <= '9'; 158 '0' <= arg[2] && arg[2] <= '9';
154} 159}
155 160
156static int 161static int
157parse_flags(const char *arg, int *qdisp, int *flags, char status[]) 162parse_flags(const char *arg, int *qdisp, int *flags, int *match, char status[])
158{ 163{
159 struct wordsplit ws; 164 struct wordsplit ws;
160 int rc = 0; 165 int rc = 0;
161 int i; 166 int i;
162 167
163 if (!arg) 168 if (!arg)
@@ -201,12 +206,16 @@ parse_flags(const char *arg, int *qdisp, int *flags, char status[])
201 rc = 1; 206 rc = 1;
202 } else { 207 } else {
203 strncpy(status, ws.ws_wordv[i] + 2, 208 strncpy(status, ws.ws_wordv[i] + 2,
204 HTTP_STATUS_LEN); 209 HTTP_STATUS_LEN);
205 status[HTTP_STATUS_LEN] = 0; 210 status[HTTP_STATUS_LEN] = 0;
206 } 211 }
212 } else if (strcmp(ws.ws_wordv[i], "regex") == 0) {
213 *match = MATCH_REGEX;
214 } else if (strcmp(ws.ws_wordv[i], "eq") == 0) {
215 *match = MATCH_EQ;
207 } else { 216 } else {
208 dbrw_error("unrecognized flag: %s", ws.ws_wordv[i]); 217 dbrw_error("unrecognized flag: %s", ws.ws_wordv[i]);
209 rc = 1; 218 rc = 1;
210 } 219 }
211 } 220 }
212 221
@@ -274,19 +283,21 @@ vmod_config(VRT_CTX, struct vmod_priv *priv,
274 conf->idle_timeout = atoi(s); 283 conf->idle_timeout = atoi(s);
275 else 284 else
276 conf->idle_timeout = -2; 285 conf->idle_timeout = -2;
277 286
278 conf->qdisp = QDISP_NONE; 287 conf->qdisp = QDISP_NONE;
279 conf->regflags = REG_EXTENDED; 288 conf->regflags = REG_EXTENDED;
289 conf->match_type = MATCH_REGEX;
280 conf->status[0] = 0; 290 conf->status[0] = 0;
281 291
282 s = findparam(conf->param, "flags"); 292 s = findparam(conf->param, "flags");
283 if (s) 293 if (s)
284 parse_flags(s, 294 parse_flags(s,
285 &conf->qdisp, 295 &conf->qdisp,
286 &conf->regflags, 296 &conf->regflags,
297 &conf->match_type,
287 conf->status); 298 conf->status);
288 299
289 AZ(pthread_mutex_lock(&config_pool_mtx)); 300 AZ(pthread_mutex_lock(&config_pool_mtx));
290 VTAILQ_INSERT_HEAD(&config_pool, conf, list); 301 VTAILQ_INSERT_HEAD(&config_pool, conf, list);
291 pthread_mutex_unlock(&config_pool_mtx); 302 pthread_mutex_unlock(&config_pool_mtx);
292 } 303 }
@@ -410,12 +421,13 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
410 regex_t re; 421 regex_t re;
411 int rc; 422 int rc;
412 size_t matchcount; /* Number of used entries in matches */ 423 size_t matchcount; /* Number of used entries in matches */
413 int rflags = conn->conf->regflags; 424 int rflags = conn->conf->regflags;
414 char status[HTTP_STATUS_LEN+1]; 425 char status[HTTP_STATUS_LEN+1];
415 int qdisp = conn->conf->qdisp; 426 int qdisp = conn->conf->qdisp;
427 int match_type = conn->conf->match_type;
416 char *qry = NULL; 428 char *qry = NULL;
417 429
418 if (ISEMPTY(pat)) { 430 if (ISEMPTY(pat)) {
419 res = WS_Copy(WSPTR(ctx), sql_get_column(conn, i, 0), -1); 431 res = WS_Copy(WSPTR(ctx), sql_get_column(conn, i, 0), -1);
420 break; 432 break;
421 } 433 }
@@ -432,13 +444,13 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
432 debug(conn->conf, 1, ("expanded to \"%s\" ~ \"%s\"", 444 debug(conn->conf, 1, ("expanded to \"%s\" ~ \"%s\"",
433 pat, val)); 445 pat, val));
434 446
435 strcpy(status, conn->conf->status); 447 strcpy(status, conn->conf->status);
436 if (nf == 4) { 448 if (nf == 4) {
437 if (parse_flags(sql_get_column(conn, i, 3), 449 if (parse_flags(sql_get_column(conn, i, 3),
438 &qdisp, &rflags, status)) 450 &qdisp, &rflags, &match_type, status))
439 continue; 451 continue;
440 } 452 }
441 453
442 switch (qdisp) { 454 switch (qdisp) {
443 case QDISP_NONE: 455 case QDISP_NONE:
444 break; 456 break;
@@ -453,44 +465,51 @@ findmatch(VRT_CTX, struct dbrw_connection *conn, char **param)
453 debug(conn->conf, 1, 465 debug(conn->conf, 1,
454 ("discarding query part \"%s\"", qry)); 466 ("discarding query part \"%s\"", qry));
455 *qry = 0; 467 *qry = 0;
456 qry = NULL; 468 qry = NULL;
457 } 469 }
458 } 470 }
459
460 rc = regcomp(&re, pat, rflags);
461 if (rc) {
462 char errbuf[512];
463
464 regerror(rc, &re, errbuf, sizeof(errbuf));
465 dbrw_error("cannot compile regexp \"%s\": %s",
466 pat, errbuf);
467 continue;
468 }
469 471
470 matchcount = re.re_nsub + 1; 472 if (match_type == MATCH_EQ) {
471 if (conn->matchsize < matchcount) { 473 rc = ((rflags & REG_ICASE)
472 void *p = realloc(conn->matches, 474 ? strcasecmp : strcmp) (pat, val);
473 sizeof(conn->matches[0]) * matchcount); 475 } else {
474 if (!p) { 476 rc = regcomp(&re, pat, rflags);
475 dbrw_error("not enough memory"); 477 if (rc) {
476 regfree(&re); 478 char errbuf[512];
479
480 regerror(rc, &re, errbuf, sizeof(errbuf));
481 dbrw_error("cannot compile regexp \"%s\": %s",
482 pat, errbuf);
477 continue; 483 continue;
478 } 484 }
479 conn->matches = p;
480 conn->matchsize = matchcount;
481 }
482 485
483 rc = regexec(&re, val, matchcount, conn->matches, 0); 486 matchcount = re.re_nsub + 1;
487 if (conn->matchsize < matchcount) {
488 void *p = realloc(conn->matches,
489 sizeof(conn->matches[0]) * matchcount);
490 if (!p) {
491 dbrw_error("not enough memory");
492 regfree(&re);
493 continue;
494 }
495 conn->matches = p;
496 conn->matchsize = matchcount;
497 }
498
499 rc = regexec(&re, val, matchcount, conn->matches, 0);
484 500
485 if (rc == 0) 501 if (rc == 0)
486 res = expand_backref(ctx, val, 502 res = expand_backref(ctx, val,
487 sql_get_column(conn, i, 0), 503 sql_get_column(conn, i, 0),
488 matchcount, conn->matches, qry); 504 matchcount,
505 conn->matches, qry);
489 506
490 regfree(&re); 507 regfree(&re);
508 }
509
491 if (rc == 0) { 510 if (rc == 0) {
492 debug(conn->conf, 1, ("match")); 511 debug(conn->conf, 1, ("match"));
493 if (status[0]) { 512 if (status[0]) {
494 debug(conn->conf, 1, 513 debug(conn->conf, 1,
495 ("setting status %s", status)); 514 ("setting status %s", status));
496 dbrw_sethdr(ctx, HDR_REQ, 515 dbrw_sethdr(ctx, HDR_REQ,
@@ -603,39 +622,40 @@ query_command_expand(char **ret, const char *cmd, size_t len, char **argv,
603 return ec->exp(clos, argv, ret); 622 return ec->exp(clos, argv, ret);
604 } 623 }
605 624
606 return expand_error(ret, argv[0], "unknown command"); 625 return expand_error(ret, argv[0], "unknown command");
607} 626}
608 627
609static char * 628static int
610do_rewrite(VRT_CTX, struct dbrw_connection *cp, VCL_STRING arg) 629do_rewrite(VRT_CTX, struct dbrw_connection *cp, VCL_STRING arg, char **result)
611{ 630{
612 struct wordsplit ws, wsenv; 631 struct wordsplit ws, wsenv;
613 int i, rc; 632 int i, rc;
614 char *res;
615 int wsflags; 633 int wsflags;
634
635 *result = NULL;
616 636
617 if (sql_connect(cp) || cp->state != state_connected) 637 if (sql_connect(cp) || cp->state != state_connected)
618 return NULL; 638 return -1;
619 639
620 debug(cp->conf, 2, ("vmod_rewrite: splitting arg")); 640 debug(cp->conf, 2, ("vmod_rewrite: splitting arg"));
621 wsenv.ws_delim = ";"; 641 wsenv.ws_delim = ";";
622 if (wordsplit(arg, &wsenv, WRDSF_NOVAR|WRDSF_NOCMD|WRDSF_DELIM)) { 642 if (wordsplit(arg, &wsenv, WRDSF_NOVAR|WRDSF_NOCMD|WRDSF_DELIM)) {
623 dbrw_error("cannot split string `%s': %s", 643 dbrw_error("cannot split string `%s': %s",
624 arg, wordsplit_strerror(&wsenv)); 644 arg, wordsplit_strerror(&wsenv));
625 return NULL; 645 return -1;
626 } 646 }
627 647
628 if (cp->conf->backend->sql_escape) { 648 if (cp->conf->backend->sql_escape) {
629 debug(cp->conf, 2, ("escaping variables")); 649 debug(cp->conf, 2, ("escaping variables"));
630 for (i = 0; i < wsenv.ws_wordc; i++) { 650 for (i = 0; i < wsenv.ws_wordc; i++) {
631 char *p = sql_escape(cp, wsenv.ws_wordv[i]); 651 char *p = sql_escape(cp, wsenv.ws_wordv[i]);
632 if (!p) { 652 if (!p) {
633 dbrw_error("cannot expand argument"); 653 dbrw_error("cannot expand argument");
634 wordsplit_free(&wsenv); 654 wordsplit_free(&wsenv);
635 return NULL; 655 return -1;
636 } 656 }
637 free(wsenv.ws_wordv[i]); 657 free(wsenv.ws_wordv[i]);
638 wsenv.ws_wordv[i] = p; 658 wsenv.ws_wordv[i] = p;
639 debug(cp->conf, 3, ("%d: %s",i,p)); 659 debug(cp->conf, 3, ("%d: %s",i,p));
640 } 660 }
641 } 661 }
@@ -654,42 +674,46 @@ do_rewrite(VRT_CTX, struct dbrw_connection *cp, VCL_STRING arg)
654 rc = wordsplit(cp->conf->query, &ws, wsflags); 674 rc = wordsplit(cp->conf->query, &ws, wsflags);
655 675
656 if (rc) { 676 if (rc) {
657 dbrw_error("cannot expand query `%s': %s", 677 dbrw_error("cannot expand query `%s': %s",
658 cp->conf->query, wordsplit_strerror(&ws)); 678 cp->conf->query, wordsplit_strerror(&ws));
659 wordsplit_free(&wsenv); 679 wordsplit_free(&wsenv);
660 return NULL; 680 return -1;
661 } 681 }
662 682
663 rc = sql_query(cp, ws.ws_wordv[0]); 683 rc = sql_query(cp, ws.ws_wordv[0]);
664 wordsplit_free(&ws); 684 wordsplit_free(&ws);
665 685
666 if (rc) { 686 if (rc) {
667 debug(cp->conf, 1, ("vmod_rewrite: query failed")); 687 dbrw_error("vmod_rewrite: query failed");
668 wordsplit_free(&wsenv); 688 wordsplit_free(&wsenv);
669 return NULL; 689 return -1;
670 } 690 }
671 691
672 res = findmatch(ctx, cp, wsenv.ws_wordv); 692 *result = findmatch(ctx, cp, wsenv.ws_wordv);
673 wordsplit_free(&wsenv); 693 wordsplit_free(&wsenv);
674 694
675 sql_free_result(cp); 695 sql_free_result(cp);
676 696
677 return res; 697 return 0;
678} 698}
679 699
680VCL_STRING 700VCL_STRING
681vmod_rewrite(VRT_CTX, struct vmod_priv *priv, VCL_STRING arg) 701vmod_rewrite(VRT_CTX, struct vmod_priv *priv, VCL_STRING arg)
682{ 702{
683 struct dbrw_config *conf = priv->priv; 703 struct dbrw_config *conf = priv->priv;
684 struct dbrw_connection *cp; 704 struct dbrw_connection *cp;
685 char *res = NULL; 705 char *res = NULL;
686 706 int rc;
707
687 AN(conf); 708 AN(conf);
688 debug(conf, 2, ("vmod_rewrite(%s) begin", arg)); 709 debug(conf, 2, ("vmod_rewrite(%s) begin", arg));
689 cp = dbrw_connection_get(conf); 710 cp = dbrw_connection_get(conf);
690 AN(cp); 711 AN(cp);
691 res = do_rewrite(ctx, cp, arg); 712 rc = do_rewrite(ctx, cp, arg, &res);
692 dbrw_connection_release(cp); 713 dbrw_connection_release(cp);
693 debug(conf, 1, ("vmod_rewrite: res=%s", res ? res : "(NULL)")); 714 debug(conf, 1, ("vmod_rewrite: %d, res=%s", rc, res ? res : "(NULL)"));
715 if (rc) {
716 dbrw_sethdr(ctx, HDR_REQ, "\022X-VMOD-DBRW-Error:", "1");
717 }
694 return res; 718 return res;
695} 719}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 792ce24..28b795f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -46,12 +46,13 @@ TESTSUITE_AT = \
46 rewrite01.at\ 46 rewrite01.at\
47 rewrite02.at\ 47 rewrite02.at\
48 rewrite03.at\ 48 rewrite03.at\
49 rewrite04.at\ 49 rewrite04.at\
50 rewrite05.at\ 50 rewrite05.at\
51 rewrite06.at\ 51 rewrite06.at\
52 rewrite07.at\
52 testsuite.at 53 testsuite.at
53 54
54TESTSUITE = $(srcdir)/testsuite 55TESTSUITE = $(srcdir)/testsuite
55M4=m4 56M4=m4
56 57
57AUTOTEST = $(AUTOM4TE) --language=autotest 58AUTOTEST = $(AUTOM4TE) --language=autotest
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 18a0b69..14f3fd4 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -48,16 +48,23 @@ varnish v1 -vcl+backend {
48 sub vcl_recv { 48 sub vcl_recv {
49 dbrw.config("$DBRW_TEST_DBTYPE", "$DBRW_TEST_PARAMS", 49 dbrw.config("$DBRW_TEST_DBTYPE", "$DBRW_TEST_PARAMS",
50 {"$1"}); 50 {"$1"});
51 set req.http.X-Redirect-To = 51 set req.http.X-Redirect-To =
52 dbrw.rewrite("host=" + req.http.Host + ";" + 52 dbrw.rewrite("host=" + req.http.Host + ";" +
53 "url=" + req.url); 53 "url=" + req.url);
54 return(synth(301, "Redirect")); 54 if (req.http.X-Redirect-To != "") {
55 return(synth(301, "Redirect"));
56 } else if (req.http.X-VMOD-DBRW-Error == "1") {
57 return(synth(500, "DBRW Error"));
58 }
55 } 59 }
56 60
57 sub vcl_synth { 61 sub vcl_synth {
62 if (req.http.X-VMOD-DBRW-Error == "1") {
63 set resp.http.X-VMOD-DBRW-Error = "1";
64 }
58 if (resp.status == 301) { 65 if (resp.status == 301) {
59 if (req.http.X-VMOD-DBRW-Status) { 66 if (req.http.X-VMOD-DBRW-Status) {
60 set resp.status = std.integer(req.http.X-VMOD-DBRW-Status, 301); 67 set resp.status = std.integer(req.http.X-VMOD-DBRW-Status, 301);
61 } 68 }
62 set resp.http.Location = req.http.X-Redirect-To; 69 set resp.http.Location = req.http.X-Redirect-To;
63 return (deliver); 70 return (deliver);
diff --git a/tests/initdb.at b/tests/initdb.at
index 0355e3b..f7bfe0b 100644
--- a/tests/initdb.at
+++ b/tests/initdb.at
@@ -41,20 +41,20 @@ CREATE TABLE rewrite (
41 flags varchar(64) DEFAULT NULL 41 flags varchar(64) DEFAULT NULL
42); 42);
43 43
44CREATE INDEX source ON rewrite(host,url); 44CREATE INDEX source ON rewrite(host,url);
45 45
46INSERT INTO rewrite VALUES 46INSERT INTO rewrite VALUES
47('en.example.net','/local','http://uno.example.com/remote',NULL,NULL,NULL), 47('en.example.net','/local','http://uno.example.com/remote',NULL,NULL,'eq'),
48('en.example.net','/local','http://dos.example.com/$[]1','$url','/local/(.*)',NULL), 48('en.example.net','/local','http://dos.example.com/$[]1','$url','/local/(.*)',NULL),
49('en.example.net','/local2','http://to.example.net/$[]1$[]2','$url','/local2/([[^\\?]]*)(\\?.*)?',NULL), 49('en.example.net','/local2','http://to.example.net/$[]1$[]2','$url','/local2/([[^\\?]]*)(\\?.*)?',NULL),
50('to.example.net','/local','http://dos.example.net/$[]1','$url','/local/(.*)','QSA'), 50('to.example.net','/local','http://dos.example.net/$[]1','$url','/local/(.*)','QSA'),
51('tre.example.net','/local','http://dos.example.net/$[]1?i=10','$url','/local/(.*)','QSA,R=302'); 51('tre.example.net','/local','http://dos.example.net/$[]1?i=10','$url','/local/(.*)','QSA,R=302');
52 52
53EOT 53EOT
54], 54],
55[0], 55[0],
56[], 56[],
57[], 57[],
58[mv err $FAILFILE], 58[mv err $FAILFILE],
59[echo "OK" > $INITFILE]) 59[echo "OK" > $INITFILE])
60]) \ No newline at end of file 60])
diff --git a/tests/rewrite07.at b/tests/rewrite07.at
new file mode 100644
index 0000000..6554fc7
--- a/dev/null
+++ b/tests/rewrite07.at
@@ -0,0 +1,40 @@
1 # This file is part of vmod-dbrw -*- autotest -*-
2# Copyright (C) 2013-2018 Sergey Poznyakoff
3#
4# Vmod-dbrw is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option)
7# any later version.
8#
9# Vmod-dbrw is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with vmod-dbrw. If not, see <http://www.gnu.org/licenses/>.
16
17AT_SETUP(Rewrite 7 - SQL error handling)
18AT_KEYWORDS(rewrite rewrite07)
19
20AT_DBRW_INIT
21
22AT_CHECK([
23AT_DBINIT_PREREQ
24# This test simulates rewrite failure in order to check whether
25# the X-VMOD-DBRW-Error header is correctly set on return.
26AT_VCL([SELECT dest,pattern,value,flags
27 FROM rewrite
28 WHERE host='$BADHOST' AND url IN ($(urlprefixes $url))
29 ORDER BY LENGTH(dest),value DESC],
30 [txreq -url /local/foo/bar?x&y&z -hdr "Host:tre.example.net"
31 rxresp
32 expect resp.status == 500
33 expect resp.http.X-VMOD-DBRW-Error == 1
34])
35AT_VARNISHTEST
36],
37[0],
38[OK
39])
40AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 5858b6a..203b667 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -57,9 +57,10 @@ m4_include([exact01.at])
57m4_include([rewrite01.at]) 57m4_include([rewrite01.at])
58m4_include([rewrite02.at]) 58m4_include([rewrite02.at])
59m4_include([rewrite03.at]) 59m4_include([rewrite03.at])
60m4_include([rewrite04.at]) 60m4_include([rewrite04.at])
61m4_include([rewrite05.at]) 61m4_include([rewrite05.at])
62m4_include([rewrite06.at]) 62m4_include([rewrite06.at])
63m4_include([rewrite07.at])
63 64
64 65
65# End of testsuite.at 66# End of testsuite.at

Return to:

Send suggestions and report system problems to the System administrator.