diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-02-12 16:30:53 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-02-12 16:30:53 +0200 |
commit | 133e104d9efac43c0cf243207c2c5eaf0343bced (patch) | |
tree | 64399bcc3d6b33de2fb911d291ba90656b028fc1 | |
parent | c36a2210ed6cd53c5c65418fa9c20ac22dec8c59 (diff) | |
download | vmod-variable-133e104d9efac43c0cf243207c2c5eaf0343bced.tar.gz vmod-variable-133e104d9efac43c0cf243207c2c5eaf0343bced.tar.bz2 |
Improve batchset
The new syntax allows for supplying replacement patterns as in
variable.batchset("x:duration=\2s", ...
* configure.ac: Remove unneeded check
* src/variable.c (vardef): New member repl.
(bref_expand): New function.
(vmod_batchset): Change handling of vars string.
* tests/batchset.at: Update.
-rw-r--r-- | configure.ac | 18 | ||||
-rw-r--r-- | src/variable.c | 139 | ||||
-rw-r--r-- | tests/batchset.at | 6 |
3 files changed, 101 insertions, 62 deletions
diff --git a/configure.ac b/configure.ac index 2fa32f6..f21fcfb 100644 --- a/configure.ac +++ b/configure.ac @@ -105,30 +105,12 @@ AC_ARG_WITH([vmoddir], if test -z "$VMODDIR"; then VMODDIR='$(libdir)/varnish/mods' fi -########### -# Check for db.h and libdb -# -AC_CHECK_HEADER([db.h],,[AC_MSG_ERROR([Required header file db.h not found])]) - -AC_CHECK_LIB(db, db_create, - [LIBS="$LIBS -ldb" - AC_RUN_IFELSE( - [AC_LANG_PROGRAM([#include "db.h"], - [int v_major, v_minor, v_patch; - db_version(&v_major, &v_minor, &v_patch); - return !(v_major == DB_VERSION_MAJOR - && v_minor == DB_VERSION_MINOR - && v_patch == DB_VERSION_PATCH); - ])], - [], - [AC_MSG_ERROR([header file db.h is not the same version as libdb])])]) - AC_CONFIG_COMMANDS([status],[ delim="-------------------------------------------------------------------" echo "" echo $delim echo "Building for Varnish version $VARNISHVERSION" echo $delim diff --git a/src/variable.c b/src/variable.c index 6403c1a..9442b6b 100644 --- a/src/variable.c +++ b/src/variable.c @@ -497,13 +497,14 @@ log_error(const char *fmt, ...) #define S(s) ((s) ? (s) : "NULL") struct vardef { struct vardef *next; enum variable_type type; - char name[1]; + char *name; + char *repl; }; static void vardef_free(struct vardef *v) { while (v) { @@ -567,12 +568,57 @@ str2duration(const char *str) } while (*p && isspace(*p)) p++; return *p ? 0 : r; } +char * +bref_expand(const char *str, const char *input, pcre *re, + int ovsize, int *ovector) +{ + size_t rlen = 0; + char *rbase = NULL; + char *rptr; + int nm = 2*ovsize/3; + const char *p; + + for (p = str; *p; ) { + if (*p == '\\' && strchr("123456789", p[1])) { + int n = 2*(p[1] - '0'); + if (n < nm) { + rlen += ovector[n+1] - ovector[n]; + p += 2; + continue; + } + } + ++p; + ++rlen; + } + rbase = malloc(rlen + 1); + AN(rbase); + p = str; + rptr = rbase; + while (*p) { + if (*p == '\\' && strchr("123456789", p[1])) { + int n = 2*(p[1] - '0'); + if (n < nm) { + memcpy(rptr, input + ovector[n], + ovector[n+1] - ovector[n]); + rptr += ovector[n+1] - ovector[n]; + p += 2; + continue; + } + } + + *rptr++ = *p++; + } + *rptr = 0; + + return rbase; +} + VCL_VOID vmod_batchset(VARIABLE_CTX ctx, VCL_STRING vars, VCL_STRING rxs, VCL_STRING input) { struct symtab *vt = get_symtab(ctx); struct vardef *head = NULL, *tail = NULL, *def; @@ -595,56 +641,69 @@ vmod_batchset(VARIABLE_CTX ctx, log_error("variable.batchset: bad arguments: vars=%s, rxs=%s, input=%s", S(vars), S(rxs), S(input)); return; } while (*v) { - size_t n = strcspn(v, "="); + char const *nameptr = v; + size_t n = strcspn(v, ":=,"); + size_t namelen; + char const *replptr; + size_t repllen; + char rbuf[3]; + enum variable_type type; + int delim; + + namelen = n; - if (!v[n]) { - log_error("variable.batchset: vars argument invalid near %s", - v); - vardef_free(head); - return; + v += n; + delim = *v ? *v++ : 0; + + if (delim == ':') { + n = strcspn(v, "=,"); + type = str2type(v, n); + v += n; + delim = *v ? *v++ : 0; + } else + type = variable_string; + + if (delim == '=') { + n = strcspn(v, ","); + replptr = v; + repllen = n; + v += n; + delim = *v ? *v++ : 0; + } else { + rbuf[0] = '\\'; + rbuf[1] = count + '1'; + rbuf[2] = 0; + replptr = rbuf; + repllen = 2; } - def = malloc(sizeof(def[0]) + n); + + def = malloc(sizeof(def[0]) + namelen + repllen + 2); def->next = NULL; - memcpy(def->name, v, n); - def->name[n] = 0; if (tail) tail->next = def; else head = def; tail = def; ++count; - - v += n + 1; - if (!*v) { - log_error("variable.batchset: no type for %s", def->name); - vardef_free(head); - return; - } - - n = strcspn(v, ","); - def->type = str2type(v, n); - if (def->type == variable_unset) { - log_error("variable.batchset: invalid type for %s", - def->name); - vardef_free(head); - return; - } - - v += n; - if (*v) - ++v; + def->type = type; + def->name = (char*)(def + 1); + memcpy(def->name, nameptr, namelen); + def->name[namelen] = 0; + def->repl = def->name + namelen + 1; + memcpy(def->repl, replptr, repllen); + def->repl[repllen] = 0; } re = pcre_compile(rxs, cflags, &error_ptr, &error_offset, NULL); if (!re) { log_error("variable.batchset: %s: compilation failed near %s: %s", - rxs, rxs + error_offset, error_ptr); + rxs, rxs + error_offset, error_ptr); vardef_free(head); return; } rc = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &n); if (rc) { @@ -670,22 +729,14 @@ vmod_batchset(VARIABLE_CTX ctx, else /*FIXME*/; vardef_free(head); return; } - for (def = head, i = 1; def; def = def->next, i++) { - const char *s; - - rc = pcre_get_substring(input, ovector, ovsize, i, &s); - if (rc < 0) { - log_error("variable.batchset: %s(%s) can't get subexpr #%d: %d", - rxs, input, i, rc); - vardef_free(head); - return; - } + for (def = head; def; def = def->next, i++) { + char *s = bref_expand(def->repl, input, re, ovsize, ovector); switch (def->type) { case variable_string: value.s = (char*)s; break; case variable_int: @@ -701,33 +752,37 @@ vmod_batchset(VARIABLE_CTX ctx, } else if (lval < INT_MIN || lval > INT_MAX) { log_error("variable.batchset: %s(%s)#%d: value out of range", rxs, input, i); value.i = 0; } else value.i = lval; + free(s); break; case variable_real: errno = 0; value.r = strtod(s, &p); if (*p) { log_error("variable.batchset: %s(%s)#%d: not a valid number", rxs, input, i); value.r = 0; } else if (errno) { log_error("variable.batchset: %s(%s)#%d: %s", rxs, input, i, strerror(errno)); value.r = 0; } + free(s); break; case variable_duration: value.d = str2duration(s); - break; + free(s); + break; default: abort(); } defvar(vt, def->name, def->type, &value); } pcre_free(re); free(ovector); vardef_free(head); } + diff --git a/tests/batchset.at b/tests/batchset.at index be07cae..506fe78 100644 --- a/tests/batchset.at +++ b/tests/batchset.at @@ -16,22 +16,24 @@ AT_SETUP(batchset) AT_KEYWORDS(batchset) AT_VARNISHTEST([ sub vcl_recv { - variable.batchset("y=i,x=s", "^/(\d+)/(.+)", req.url); + variable.batchset("y:i,x,time:d=\3s", "^/(\d+)/(.+)/(\d+)", req.url); } sub vcl_deliver { set resp.http.X-X = variable.get("x"); set resp.http.X-Y = variable.get_int("y"); + set resp.http.X-Time = variable.get_duration("time"); } ],[ -txreq -url /10/test +txreq -url /10/test/60 rxresp expect resp.http.X-X == "test" expect resp.http.X-Y == "10" +expect resp.http.X-Time == "60.000" ]) AT_CLEANUP
\ No newline at end of file |