[master] 489460a Ported the boltsort vmod to 4.0 and included it in the std vmod as discussed on the latest vdd.

Per Buer perbu at varnish-software.com
Sat Jun 21 18:42:24 CEST 2014


commit 489460a7ab218f1dc4303b0baeec1bdfa9b4da38
Author: Per Buer <perbu at varnish-software.com>
Date:   Sat Jun 21 18:21:04 2014 +0200

    Ported the boltsort vmod to 4.0 and included it
    in the std vmod as discussed on the latest vdd.
    
    Renamed it to std.querysort. Two tests where
    included. They both pass on my machine.

diff --git a/bin/varnishtest/tests/m00014.vtc b/bin/varnishtest/tests/m00014.vtc
new file mode 100644
index 0000000..db2a62e
--- /dev/null
+++ b/bin/varnishtest/tests/m00014.vtc
@@ -0,0 +1,68 @@
+varnishtest "Test querysort in std vmod"
+
+server s1 {
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+    rxreq
+    txresp
+
+} -start
+
+varnish v1 -vcl+backend {
+
+    import ${vmod_std};
+    sub vcl_deliver {
+        set resp.http.naren = std.querysort(req.url);
+    }
+
+} -start
+
+client c1 {
+
+    txreq -url "/video/44505073?title=0&byline=0&portrait=0&color=51a516"
+    rxresp
+    expect resp.http.naren == "/video/44505073?byline=0&color=51a516&portrait=0&title=0"
+
+    txreq -url "/video/44505073?byline=0&&&&&"
+    rxresp
+    expect resp.http.naren == "/video/44505073?byline=0"
+
+    txreq -url "/video/2?&"
+    rxresp
+    expect resp.http.naren == "/video/2?"
+
+    txreq -url "/video/2"
+    rxresp
+    expect resp.http.naren == "/video/2"
+
+    txreq -url "/video/2?cod=cape&cape=cod"
+    rxresp
+    expect resp.http.naren == "/video/2?cape=cod&cod=cape"
+
+    txreq -url "/"
+    rxresp
+    expect resp.http.naren == "/"
+
+}
+
+client c1 -run
diff --git a/bin/varnishtest/tests/m00015.vtc b/bin/varnishtest/tests/m00015.vtc
new file mode 100644
index 0000000..47109c8
--- /dev/null
+++ b/bin/varnishtest/tests/m00015.vtc
@@ -0,0 +1,75 @@
+varnishtest "Test querysort of req.url in vcl_hash"
+
+server s1 {
+
+    rxreq
+    txresp
+    rxreq
+    txresp
+
+} -start
+
+varnish v1 -vcl+backend {
+
+    import ${vmod_std};
+
+    sub vcl_hash {
+        set req.url = std.querysort(req.url);
+    }
+
+    sub vcl_deliver {
+        if (obj.hits > 0) {
+            set resp.http.X-Cache = "HIT";
+        }
+        else {
+            set resp.http.X-Cache = "MISS";
+        }
+    }
+
+} -start
+
+client c1 {
+
+    txreq -url "/video/47013255?title=0&byline=0&portrait=0&autoplay=1"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.X-Cache == "MISS"
+
+    txreq -url "/video/47013255?title=0&byline=0&portrait=0&autoplay=1"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.X-Cache == "HIT"
+
+}
+
+client c2 {
+
+    txreq -url "/video/47013255?autoplay=1&title=0&byline=0&portrait=0"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.X-Cache == "HIT"
+
+    txreq -url "autoplay=1&title=0&byline=0&portrait=0&&&&"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.X-Cache == "HIT"
+
+}
+
+client c2 {
+
+    txreq -url "/video/47013255?autoplay=1&title=0&byline=0&portrait=0"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.X-Cache == "HIT"
+
+    txreq -url "/video/47013255?autoplay=1&title=0&byline=0&portrait=0&&&&"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.X-Cache == "HIT"
+
+}
+
+
+client c1 -run
+client c2 -run
diff --git a/lib/libvmod_std/vmod.vcc b/lib/libvmod_std/vmod.vcc
index 7a22156..0be272e 100644
--- a/lib/libvmod_std/vmod.vcc
+++ b/lib/libvmod_std/vmod.vcc
@@ -155,6 +155,16 @@ Description
 Example
 	std.timestamp("curl-request");
 
+$Function STRING querysort(STRING)
+
+Description
+        Sorts the querystring for cache normalization purposes.
+
+Example
+        set req.url = std.querysort(req.url);
+
+
+
 SEE ALSO
 ========
 
@@ -173,3 +183,4 @@ COPYRIGHT
 
 This document is licensed under the same licence as Varnish
 itself. See LICENCE for details.
+
diff --git a/lib/libvmod_std/vmod_std.c b/lib/libvmod_std/vmod_std.c
index 233c2da..bedbd7d 100644
--- a/lib/libvmod_std/vmod_std.c
+++ b/lib/libvmod_std/vmod_std.c
@@ -225,3 +225,140 @@ vmod_timestamp(const struct vrt_ctx *ctx, VCL_STRING label)
 		VSLb_ts_req(ctx->req, label, VTIM_real());
 	}
 }
+
+
+/* Boltsort
+   Author: Naren Venkataraman of Vimeo Inc.
+
+   Included here with permission.
+*/
+
+
+#define QS_MAX_PARAM_COUNT 32
+#define QS_EQUALS(c, h) ((c == h) || (c == '\0' && h == '&') || (c == '&' && h == '\0'))
+#define QS_ENDS(s) (s == '&' || s == '\0') 
+
+static const char QS_TERMINATORS[2] = {'\0', '&'};
+
+//since we dont store param length, we have to evaluate everytime
+static inline int param_compare (char *s, char *t)
+{
+
+    for ( ;QS_EQUALS(*s, *t); s++, t++) {
+        if (QS_ENDS(*s)) {
+            return 0;
+        }
+    }
+    return *s - *t;
+
+}
+
+//end of param is either first occurance of & or '\0'
+static inline int param_copy(char *dst, char *src, char *last_param)
+{
+
+    int len = strchr(src, QS_TERMINATORS[(src != last_param)]) - src;
+    memcpy(dst, src, len);
+    return len;
+
+}
+
+//Varnish vmod requires this
+int init_function(struct vmod_priv *priv, const struct VCL_conf *conf)
+{
+    return 0;
+
+}
+
+//sort query string
+VCL_STRING vmod_querysort(const struct vrt_ctx * ctx, VCL_STRING url)
+{
+
+    if (url == NULL) {
+        return NULL;
+    }
+
+    int qs_index = 0;
+    int param_count = 0;
+
+    char *dst_url = NULL;
+    char *qs = NULL;
+
+    //To avoid 1 pass for count calculations, assuming MAX_PARAM_COUNT as max
+    char* params[QS_MAX_PARAM_COUNT];
+
+    int i, p;
+    char *param = NULL;
+
+    qs = strchr(url, '?');
+    if(!qs) {
+        return url;
+    }
+
+    //add first param and increment count
+    params[param_count++] = ++qs;
+    qs_index = qs - url;
+
+    //Continue to find query string
+    while((qs = strchr(qs, '&')) != NULL) {
+        param = ++qs;
+
+        for(p = 0; p < param_count; p++) {
+            //if incoming param is < param at position then place it at p and then move up rest
+            if(param[0] < params[p][0] || param_compare(param, params[p]) < 0) {
+                for(i = param_count; i > p; i--) {
+                    params[i] = params[i-1];
+                }
+                break;
+            }
+        }
+        params[p] = param;
+        param_count++;
+
+        //if it exceed max params return as is
+        if (param_count == QS_MAX_PARAM_COUNT) {
+            return url;
+        }
+    }
+
+    //there is nothing after & 
+    //eg: http://127.0.0.1/?me=1&
+    if (param_count == 1) {
+        return url;
+    }
+
+    //allocate space for sorted url
+    //    struct ws *ws = sp->wrk->ws; 
+    struct ws *ws = ctx->ws;
+    dst_url = WS_Alloc(ws, strchr(param, '\0') - url + 1);
+    WS_Assert(ws);
+
+    //if alloc fails return as is
+    if(dst_url == NULL) {
+        return url;
+    }
+
+    //copy data before query string
+    char* cp = memcpy(dst_url, url, qs_index) + qs_index;
+
+    //get rid of all empty params /test/?a&&&
+    for(p = 0; p < param_count - 1; p++) { 
+        if (params[p][0] != '\0' && params[p][0] != '&') {
+            break;
+        }
+    }
+
+    //copy sorted params
+    for(; p < param_count - 1; p++) {
+        //copy and increment
+        cp += param_copy(cp, params[p], param);
+        *cp++ = '&';
+    }
+
+    //copy the last param
+    cp += param_copy(cp, params[p], param);
+    *cp = '\0';
+
+    return dst_url;
+
+}



More information about the varnish-commit mailing list