Commit ba187152 authored by Geoff Simmons's avatar Geoff Simmons

Add the integer() function.

parent 55575021
Pipeline #218 skipped
...@@ -30,6 +30,7 @@ CONTENTS ...@@ -30,6 +30,7 @@ CONTENTS
* BOOL same(BLOB, BLOB) * BOOL same(BLOB, BLOB)
* BOOL equal(BLOB, BLOB) * BOOL equal(BLOB, BLOB)
* INT length(BLOB) * INT length(BLOB)
* INT integer(BLOB, ENUM {LPAD,RPAD})
* STRING version() * STRING version()
.. _func_same: .. _func_same:
...@@ -41,10 +42,8 @@ same ...@@ -41,10 +42,8 @@ same
BOOL same(BLOB, BLOB) BOOL same(BLOB, BLOB)
Description Returns true if and only if the two BLOB arguments are the same
Returns true if and only if the two BLOB arguments are the object, i.e. they specify exactly the same region of memory.
same object, i.e. they specify exactly the same region of
memory.
.. _func_equal: .. _func_equal:
...@@ -55,9 +54,8 @@ equal ...@@ -55,9 +54,8 @@ equal
BOOL equal(BLOB, BLOB) BOOL equal(BLOB, BLOB)
Description Returns true if and only if the two BLOB arguments have equal contents
Returns true if and only if the two BLOB arguments have equal (possibly in different memory regions).
contents (possibly in different memory regions).
.. _func_length: .. _func_length:
...@@ -68,8 +66,36 @@ length ...@@ -68,8 +66,36 @@ length
INT length(BLOB) INT length(BLOB)
Description Returns the length of the BLOB.
Returns the length of the BLOB.
.. _func_integer:
integer
-------
::
INT integer(BLOB, ENUM {LPAD,RPAD} padding="LPAD")
Returns the initial bytes of the BLOB as an integer.
If the BLOB has fewer bytes than the size of an INT, then the return
value is padded with zeroes to the left if ``padding`` is ``LPAD``, or
to the right if ``padding`` is ``RPAD``. That is, when ``padding`` is
``RPAD``, then the initial bytes of the BLOB are bit-shifted to the
left so that the size of an INT is filled. ``padding`` is ``LPAD`` by
default.
The value of the returned integer results from the bytes from the BLOB
in ascending order of addresses interpreted according to the
endianness of the system on which Varnish is running.
If the length of the BLOB is 0, then ``integer()`` returns 0 and emits
an error message to the Varnish log using the ``VCL_Error`` tag. If
this happens when ``integer()`` is called in ``vcl_init``, then the
VCL load fails with the error message. If it happens in any other VCL
subroutine, then VCL processing continues. Since 0 can be a legitimate
return value, you should monitor the Varnish log for the error.
.. _func_version: .. _func_version:
...@@ -80,18 +106,18 @@ version ...@@ -80,18 +106,18 @@ version
STRING version() STRING version()
Description Returns the version string for this VMOD.
Returns the version string for this VMOD.
Example::
Example std.log("Using VMOD blob version " + blob.version());
std.log("Using VMOD blob version " + blob.version());
COPYRIGHT COPYRIGHT
========= =========
:: ::
Copyright (c) 2016 UPLEX Nils Goroll Systemoptimierung Copyright (c) 2016-2017 UPLEX Nils Goroll Systemoptimierung
All rights reserved All rights reserved
Author: Geoffrey Simmons <geoffrey.simmons@uplex.de> Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
......
...@@ -123,6 +123,9 @@ varnish v1 -vcl { ...@@ -123,6 +123,9 @@ varnish v1 -vcl {
set resp.http.empty1len = blob.length(empty1.get()); set resp.http.empty1len = blob.length(empty1.get());
set resp.http.empty2len = blob.length(empty2.get()); set resp.http.empty2len = blob.length(empty2.get());
set resp.http.fooint = blob.integer(foo1.get());
set resp.http.hobbesint = blob.integer(hobbes1.get());
set resp.http.emptyint = blob.integer(empty1.get());
return(deliver); return(deliver);
} }
} -start } -start
...@@ -170,3 +173,118 @@ client c1 { ...@@ -170,3 +173,118 @@ client c1 {
expect resp.http.empty1len == "0" expect resp.http.empty1len == "0"
expect resp.http.empty2len == "0" expect resp.http.empty2len == "0"
} -run } -run
# integer()
varnish v1 -vcl {
import blob from "${vmod_topbuild}/src/.libs/libvmod_blob.so";
import blobcode;
backend b { .host = "${bad_ip}"; }
sub vcl_init {
# Byte values 7 to 0 in descending order
# $ printf "\x7\x6\x5\x4\x3\x2\x1\x0" | base64
new down07 = blobcode.blob(BASE64, "BwYFBAMCAQA=");
# Byte values 0 to 7 in ascending order
# $ printf "\x0\x1\x2\x3\x4\x5\x6\x7" | base64
new up07 = blobcode.blob(BASE64, "AAECAwQFBgc=");
# Byte values f down to 0
new down0f = blobcode.blob(BASE64, "Dw4NDAsKCQgHBgUEAwIBAA==");
# Byte values 0 up to f
new up0f = blobcode.blob(BASE64, "AAECAwQFBgcICQoLDA0ODw==");
# Byte values 3 down to 0
new down03 = blobcode.blob(BASE64, "AwIBAA==");
# Byte values 0 up to 3
new up03 = blobcode.blob(BASE64, "AAECAw==");
# 16 x 0xff
new minusone = blobcode.blob(BASE64, "//////////8=");
# Byte value 0x7f
new onebyte = blobcode.blob(BASE64, "fw==");
# Byte values 2 down to 0
new down02 = blobcode.blob(BASE64, "AgEA");
# Byte values 0 up to 2
new up02 = blobcode.blob(BASE64, "AAEC");
new empty = blobcode.blob(IDENTITY, "");
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.down07 = blob.integer(down07.get());
set resp.http.up07 = blob.integer(up07.get());
set resp.http.down0f = blob.integer(down0f.get());
set resp.http.up0f = blob.integer(up0f.get());
set resp.http.down03 = blob.integer(down03.get());
set resp.http.up03 = blob.integer(up03.get());
set resp.http.minusone = blob.integer(minusone.get());
set resp.http.onebyte = blob.integer(onebyte.get());
set resp.http.onebyterpad = blob.integer(onebyte.get(), RPAD);
set resp.http.down0frpad = blob.integer(down0f.get(), RPAD);
set resp.http.up0frpad = blob.integer(up0f.get(), RPAD);
set resp.http.down02 = blob.integer(down02.get());
set resp.http.down02lpad = blob.integer(down02.get(), LPAD);
set resp.http.down02rpad = blob.integer(down02.get(), RPAD);
set resp.http.up02 = blob.integer(up02.get());
set resp.http.up02lpad = blob.integer(up02.get(), LPAD);
set resp.http.up02rpad = blob.integer(up02.get(), RPAD);
set resp.http.empty = blob.integer(empty.get());
}
}
# Check possible values for 8-, 4- and 2-byte INTs.
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.down07 ~ "^(283686952306183|117835012|1798)$"
expect resp.http.up07 ~ "^(506097522914230528|66051|1)$"
expect resp.http.down07 != resp.http.up07
expect resp.http.down0f ~ "^(579005069656919567|252579084|3854)$"
expect resp.http.up0f ~ "^(506097522914230528|66051|1)$"
expect resp.http.up0f != resp.http.down0f
expect resp.http.down03 ~ "^(50462976|770)$"
expect resp.http.up03 ~ "^(66051|1)$"
expect resp.http.minusone == "-1"
expect resp.http.onebyte == "127"
expect resp.http.onebyterpad ~ "^(9151314442816847872|2130706432|32512)$"
expect resp.http.down0frpad == resp.http.down0f
expect resp.http.up0frpad == resp.http.up0f
expect resp.http.down02 ~ "^(131328|513)$"
expect resp.http.down02lpad == resp.http.down02
expect resp.http.down02rpad ~ "^(144396663052566528|33619968|513)$"
expect resp.http.up02 ~ "^(258|1)$"
expect resp.http.up02lpad == resp.http.up02
expect resp.http.up02rpad ~ "^(283673999966208|66048|1)$"
expect resp.http.empty == "0"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod blob error: blob length is 0 in blob.integer..$"
expect * = End
} -run
# VCL load fails if integer() is called for an empty blob in vcl_init
varnish v1 -errvcl {vmod blob error: blob length is 0 in blob.integer()} {
import blob from "${vmod_topbuild}/src/.libs/libvmod_blob.so";
import blobcode;
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new empty = blobcode.blob(IDENTITY, "");
if (blob.integer(empty.get()) == 0) {
new B = blobcode.blob(IDENTITY, "b");
}
}
}
...@@ -25,14 +25,46 @@ ...@@ -25,14 +25,46 @@
* *
*/ */
#include "config.h"
#include <string.h> #include <string.h>
#include "config.h" #include "vcl.h"
#include "vas.h"
#include "vdef.h" #include "vdef.h"
#include "vrt.h" #include "vrt.h"
#include "cache/cache.h"
#include "vsb.h"
#include "vcc_if.h" #include "vcc_if.h"
#define ERR(ctx, msg) \
errmsg((ctx), "vmod blob error: " msg)
#define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod blob error: " fmt, __VA_ARGS__)
static void
errmsg(VRT_CTX, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (ctx->vsl)
VSLbv(ctx->vsl, SLT_VCL_Error, fmt, args);
else
VSLv(SLT_VCL_Error, 0, fmt, args);
va_end(args);
if (ctx->method == VCL_MET_INIT) {
AN(ctx->msg);
va_start(args, fmt);
VSB_vprintf(ctx->msg, fmt, args);
va_end(args);
VRT_handling(ctx, VCL_RET_FAIL);
}
}
VCL_BOOL VCL_BOOL
vmod_same(VRT_CTX __attribute__((unused)), VCL_BLOB b1, VCL_BLOB b2) vmod_same(VRT_CTX __attribute__((unused)), VCL_BLOB b1, VCL_BLOB b2)
{ {
...@@ -55,6 +87,24 @@ vmod_length(VRT_CTX __attribute__((unused)), VCL_BLOB b) ...@@ -55,6 +87,24 @@ vmod_length(VRT_CTX __attribute__((unused)), VCL_BLOB b)
return b->len; return b->len;
} }
VCL_INT
vmod_integer(VRT_CTX, VCL_BLOB b, VCL_ENUM padding)
{
VCL_INT i = 0;
if (b->len >= sizeof(VCL_INT))
return *((VCL_INT *) b->priv);
if (b->len == 0) {
ERR(ctx, "blob length is 0 in blob.integer()");
return 0;
}
for (int j = 0; j < b->len; j++)
i |= ((unsigned char *)b->priv)[j] << ((b->len - j - 1) * 8);
if (padding[0] == 'R')
i <<= (sizeof(VCL_INT) - b->len) * 8;
return i;
}
VCL_STRING VCL_STRING
vmod_version(VRT_CTX __attribute__((unused))) vmod_version(VRT_CTX __attribute__((unused)))
{ {
......
#- #-
# Copyright (c) 2016 UPLEX Nils Goroll Systemoptimierung # Copyright (c) 2016-2017 UPLEX Nils Goroll Systemoptimierung
# All rights reserved # All rights reserved
# #
# Author: Geoffrey Simmons <geoffrey.simmons@uplex.de> # Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
...@@ -11,26 +11,44 @@ $Module blob 3 basic operations for the VCL blob type ...@@ -11,26 +11,44 @@ $Module blob 3 basic operations for the VCL blob type
$Function BOOL same(BLOB, BLOB) $Function BOOL same(BLOB, BLOB)
Description Returns true if and only if the two BLOB arguments are the same
Returns true if and only if the two BLOB arguments are the object, i.e. they specify exactly the same region of memory.
same object, i.e. they specify exactly the same region of
memory.
$Function BOOL equal(BLOB, BLOB) $Function BOOL equal(BLOB, BLOB)
Description Returns true if and only if the two BLOB arguments have equal contents
Returns true if and only if the two BLOB arguments have equal (possibly in different memory regions).
contents (possibly in different memory regions).
$Function INT length(BLOB) $Function INT length(BLOB)
Description Returns the length of the BLOB.
Returns the length of the BLOB.
$Function INT integer(BLOB, ENUM { LPAD, RPAD } padding="LPAD")
Returns the initial bytes of the BLOB as an integer.
If the BLOB has fewer bytes than the size of an INT, then the return
value is padded with zeroes to the left if ``padding`` is ``LPAD``, or
to the right if ``padding`` is ``RPAD``. That is, when ``padding`` is
``RPAD``, then the initial bytes of the BLOB are bit-shifted to the
left so that the size of an INT is filled. ``padding`` is ``LPAD`` by
default.
The value of the returned integer results from the bytes from the BLOB
in ascending order of addresses interpreted according to the
endianness of the system on which Varnish is running.
If the length of the BLOB is 0, then ``integer()`` returns 0 and emits
an error message to the Varnish log using the ``VCL_Error`` tag. If
this happens when ``integer()`` is called in ``vcl_init``, then the
VCL load fails with the error message. If it happens in any other VCL
subroutine, then VCL processing continues. Since 0 can be a legitimate
return value, you should monitor the Varnish log for the error.
$Function STRING version() $Function STRING version()
Description Returns the version string for this VMOD.
Returns the version string for this VMOD.
Example::
Example std.log("Using VMOD blob version " + blob.version());
std.log("Using VMOD blob version " + blob.version());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment