From 133e104d9efac43c0cf243207c2c5eaf0343bced Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 12 Feb 2015 16:30:53 +0200 Subject: 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. --- configure.ac | 18 ------- src/variable.c | 139 +++++++++++++++++++++++++++++++++++++----------------- 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 @@ -108,24 +108,6 @@ 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 "" diff --git a/src/variable.c b/src/variable.c index 6403c1a..9442b6b 100644 --- a/src/variable.c +++ b/src/variable.c @@ -500,7 +500,8 @@ log_error(const char *fmt, ...) struct vardef { struct vardef *next; enum variable_type type; - char name[1]; + char *name; + char *repl; }; static void @@ -570,6 +571,51 @@ str2duration(const char *str) 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) @@ -598,50 +644,63 @@ vmod_batchset(VARIABLE_CTX ctx, } 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; } @@ -673,16 +732,8 @@ vmod_batchset(VARIABLE_CTX ctx, 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: @@ -704,6 +755,7 @@ vmod_batchset(VARIABLE_CTX ctx, value.i = 0; } else value.i = lval; + free(s); break; case variable_real: errno = 0; @@ -716,11 +768,13 @@ vmod_batchset(VARIABLE_CTX ctx, rxs, input, i, strerror(errno)); value.r = 0; } + free(s); break; case variable_duration: value.d = str2duration(s); - break; + free(s); + break; default: abort(); } @@ -731,3 +785,4 @@ vmod_batchset(VARIABLE_CTX ctx, 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 @@ -19,17 +19,19 @@ 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 -- cgit v1.2.1