Commit c2372a13 authored by Geoff Simmons's avatar Geoff Simmons

Add function subblob().

Also removed assertions that BLOBs are not NULL, cannot be guaranteed.
parent 8826e917
Pipeline #222 skipped
......@@ -51,6 +51,7 @@ CONTENTS
* BOOL equal(BLOB, BLOB)
* INT length(BLOB)
* INT integer(BLOB, ENUM {LPAD,RPAD})
* BLOB subblob(BLOB, BYTES, BYTES)
* STRING version()
.. _func_same:
......@@ -125,6 +126,25 @@ 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_subblob:
subblob
-------
::
BLOB subblob(BLOB, BYTES length, BYTES offset=0)
Returns a new BLOB formed from ``length`` bytes of the BLOB argument
starting at ``offset`` bytes from the start of its memory region. The
default value of ``offset`` is 0B.
``subblob()`` fails and returns NULL if the BLOB argument is empty, or
if ``offset + length`` requires more bytes than are available in the
BLOB. If either case, an error message is written to the Varnish log
with the ``VCL_Error`` tag. If the function fails in ``vcl_init``,
then the VCL will fail to load.
.. _func_version:
version
......@@ -145,6 +165,14 @@ INSTALLATION
See `INSTALL.rst <INSTALL.rst>`_ in the source repository.
LIMITATIONS
===========
``subblob()`` obtains space for the newly created BLOB in Varnish
workspaces. If ``subblob()`` fails with "out of space" message in the
Varnish log, you may have to increase the varnishd parameters
``workspace_client`` and/or ``workspace_backend``.
SEE ALSO
========
......
# looks like -*- vcl -*-
varnishtest "same(), equal() and length()"
varnishtest "same(), equal(), length(), integer(), subblob()"
# VMOD blobcode must be installed
......@@ -288,3 +288,116 @@ varnish v1 -errvcl {vmod blob error: blob is empty in blob.integer()} {
}
}
}
# subblob()
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 0 up to 7
new up07 = blobcode.blob(BASE64, "AAECAwQFBgc=");
# Byte values 7 down to 0
new down07 = blobcode.blob(BASE64, "BwYFBAMCAQA=");
new empty = blobcode.blob(IDENTITY, "");
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.up03
= blobcode.encode(BASE64, blob.subblob(up07.get(), 4B));
set resp.http.down07060504
= blobcode.encode(BASE64, blob.subblob(down07.get(), 4B));
set resp.http.up04050607
= blobcode.encode(BASE64, blob.subblob(up07.get(), 4B, 4B));
set resp.http.down03
= blobcode.encode(BASE64, blob.subblob(down07.get(), 4B, 4B));
set resp.http.up07
= blobcode.encode(BASE64, blob.subblob(up07.get(), 8B));
set resp.http.down07
= blobcode.encode(BASE64, blob.subblob(down07.get(), 8B));
set resp.http.zerobytes
= blobcode.encode(BASE64, blob.subblob(down07.get(), 0B));
set resp.http.zerolen
= blob.length(blob.subblob(down07.get(), 0B));
set resp.http.empty
= blobcode.encode(BASE64, blob.subblob(empty.get(), 1B));
set resp.http.toolong
= blobcode.encode(BASE64, blob.subblob(up07.get(), 9B));
set resp.http.badoffset
= blobcode.encode(BASE64, blob.subblob(up07.get(), 4B, 5B));
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod blob error: blob is empty in blob.subblob..$"
expect * = VCL_Error "^vmod blob error: size 9 from offset 0 requires more bytes than blob length 8 in blob.subblob..$"
expect * = VCL_Error "^vmod blob error: size 4 from offset 5 requires more bytes than blob length 8 in blob.subblob..$"
expect * = End
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.up03 == "AAECAw=="
expect resp.http.down07060504 == "BwYFBA=="
expect resp.http.up04050607 == "BAUGBw=="
expect resp.http.down03 == "AwIBAA=="
expect resp.http.up07 == "AAECAwQFBgc="
expect resp.http.down07 == "BwYFBAMCAQA="
expect resp.http.zerobytes == ""
expect resp.http.zerolen == "0"
expect resp.http.empty == ""
expect resp.http.toolong == ""
expect resp.http.badoffset == ""
} -run
logexpect l1 -wait
# VCL load failures from subblob()
varnish v1 -errvcl {vmod blob error: blob is empty in blob.subblob()} {
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.same(empty.get(), blob.subblob(empty.get(), 0B))) {
new B = blobcode.blob(IDENTITY, "b");
}
}
}
varnish v1 -errvcl {vmod blob error: size 9 from offset 0 requires more bytes than blob length 8 in blob.subblob()} {
import blob from "${vmod_topbuild}/src/.libs/libvmod_blob.so";
import blobcode;
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new up07 = blobcode.blob(BASE64, "AAECAwQFBgc=");
if (blob.same(up07.get(), blob.subblob(up07.get(), 9B))) {
new B = blobcode.blob(IDENTITY, "b");
}
}
}
varnish v1 -errvcl {vmod blob error: size 4 from offset 5 requires more bytes than blob length 8 in blob.subblob()} {
import blob from "${vmod_topbuild}/src/.libs/libvmod_blob.so";
import blobcode;
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new up07 = blobcode.blob(BASE64, "AAECAwQFBgc=");
if (blob.same(up07.get(), blob.subblob(up07.get(), 4B, 5B))) {
new B = blobcode.blob(IDENTITY, "b");
}
}
}
......@@ -44,6 +44,21 @@
#define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod blob error: " fmt, __VA_ARGS__)
#define ERRNOMEM(ctx, msg) \
ERR((ctx), msg ", out of space")
#define VERRNOMEM(ctx, fmt, ...) \
VERR((ctx), fmt ", out of space", __VA_ARGS__)
static const struct vmod_priv null_blob[1] =
{
{
.priv = "",
.len = 0,
.free = NULL
}
};
static void
errmsg(VRT_CTX, const char *fmt, ...)
{
......@@ -68,17 +83,20 @@ errmsg(VRT_CTX, const char *fmt, ...)
VCL_BOOL
vmod_same(VRT_CTX __attribute__((unused)), VCL_BLOB b1, VCL_BLOB b2)
{
AN(b1);
AN(b2);
if (b1 == NULL && b2 == NULL)
return 1;
if (b1 == NULL || b2 == NULL)
return 0;
return b1->len == b2->len && b1->priv == b2->priv;
}
VCL_BOOL
vmod_equal(VRT_CTX __attribute__((unused)), VCL_BLOB b1, VCL_BLOB b2)
{
AN(b1);
AN(b2);
if (b1 == NULL && b2 == NULL)
return 1;
if (b1 == NULL || b2 == NULL)
return 0;
if (b1->len != b2->len)
return 0;
if (b1->priv == b2->priv)
......@@ -91,7 +109,8 @@ vmod_equal(VRT_CTX __attribute__((unused)), VCL_BLOB b1, VCL_BLOB b2)
VCL_INT
vmod_length(VRT_CTX __attribute__((unused)), VCL_BLOB b)
{
AN(b);
if (b == NULL)
return 0;
return b->len;
}
......@@ -101,13 +120,12 @@ vmod_integer(VRT_CTX, VCL_BLOB b, VCL_ENUM padding)
VCL_INT i = 0;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(b);
assert(b->len >= 0);
if (b->len == 0 || b->priv == NULL) {
if (b == NULL || b->len == 0 || b->priv == NULL) {
ERR(ctx, "blob is empty in blob.integer()");
return 0;
}
assert(b->len >= 0);
if ((unsigned)b->len >= sizeof(VCL_INT))
return *((VCL_INT *) b->priv);
......@@ -118,6 +136,45 @@ vmod_integer(VRT_CTX, VCL_BLOB b, VCL_ENUM padding)
return i;
}
VCL_BLOB
vmod_subblob(VRT_CTX, VCL_BLOB b, VCL_BYTES n, VCL_BYTES off)
{
uintptr_t snap;
struct vmod_priv *sub;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
assert(n >= 0);
assert(off >= 0);
if (b == NULL || b->len == 0 || b->priv == NULL) {
ERR(ctx, "blob is empty in blob.subblob()");
return NULL;
}
assert(b->len >= 0);
if (off + n > b->len) {
VERR(ctx, "size %d from offset %d requires more bytes than "
"blob length %d in blob.subblob()", n, off, b->len);
return NULL;
}
if (n == 0)
return null_blob;
snap = WS_Snapshot(ctx->ws);
if ((sub = WS_Alloc(ctx->ws, sizeof(*sub))) == NULL) {
ERRNOMEM(ctx, "Allocating BLOB result in blob.subblob()");
return NULL;
}
if ((sub->priv = WS_Alloc(ctx->ws, n)) == NULL) {
VERRNOMEM(ctx, "Allocating %d bytes in blob.subblob()", n);
WS_Reset(ctx->ws, snap);
return NULL;
}
memcpy(sub->priv, b->priv + off, n);
sub->len = n;
return sub;
}
VCL_STRING
vmod_version(VRT_CTX __attribute__((unused)))
{
......
......@@ -73,6 +73,18 @@ 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 BLOB subblob(BLOB, BYTES length, BYTES offset = 0)
Returns a new BLOB formed from ``length`` bytes of the BLOB argument
starting at ``offset`` bytes from the start of its memory region. The
default value of ``offset`` is 0B.
``subblob()`` fails and returns NULL if the BLOB argument is empty, or
if ``offset + length`` requires more bytes than are available in the
BLOB. If either case, an error message is written to the Varnish log
with the ``VCL_Error`` tag. If the function fails in ``vcl_init``,
then the VCL will fail to load.
$Function STRING version()
Returns the version string for this VMOD.
......@@ -86,6 +98,14 @@ INSTALLATION
See `INSTALL.rst <INSTALL.rst>`_ in the source repository.
LIMITATIONS
===========
``subblob()`` obtains space for the newly created BLOB in Varnish
workspaces. If ``subblob()`` fails with "out of space" message in the
Varnish log, you may have to increase the varnishd parameters
``workspace_client`` and/or ``workspace_backend``.
SEE ALSO
========
......
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