Commit 39a430d3 authored by Nils Goroll's avatar Nils Goroll

Initial release

parent c2259e0a
......@@ -10,6 +10,7 @@ m4/
*.lo
*.o
*.tar.gz
*.vcc
Makefile
Makefile.in
......@@ -26,6 +27,7 @@ stamp-h1
*.log
*.trs
*.vtc
# vmodtool
......
INSTALLATION
============
Building from source
~~~~~~~~~~~~~~~~~~~~
The VMOD is built on a system where an instance of Varnish is
installed, and the auto-tools will attempt to locate the Varnish
instance, and then pull in libraries and other support files from
there.
Quick start
-----------
This sequence should be enough in typical setups:
1. ``./bootstrap`` (for git-installation)
3. ``make``
4. ``make check`` (regression tests)
5. ``make install`` (may require root: sudo make install)
Alternative configs
-------------------
If you have installed Varnish to a non-standard directory, call
``autogen.sh`` and ``configure`` with ``PKG_CONFIG_PATH`` pointing to
the appropriate path. For example, when varnishd configure was called
with ``--prefix=$PREFIX``, use::
PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig
ACLOCAL_PATH=${PREFIX}/share/aclocal
export PKG_CONFIG_PATH ACLOCAL_PATH
Copyright 2018 UPLEX Nils Goroll Systemoptimierung
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
==============
varnish-objvar
==============
This bundle contains four varnish modules (vmods) implementing a next
level variable interface using the VCL object model:
* vmod_taskvar:
`task` scoped variables as objects: Each client or backend request
(`task`) has their own view of taskvar variables.
* vmod_topvar:
`top` scoped variables as objects: Each client request including all
esi include levels (`top`) has its own view of topvar variables.
* vmod_globalvar:
globally (per vcl) scoped variables as objects: All vcl subroutines
have the same view on variables, any change comes in effect
immediately.
* vmod_constant:
gobally (per vcl) scoped constants as objects: All vcl subroutines
have the same view on constants.
Full type support
-----------------
The vmods in this bundle aim to support all native VCL types, which
currently are:
* ``ACL``
* ``BACKEND``
* ``BLOB``
* ``BODY``
* ``BOOL``
* ``BYTES``
* ``DURATION``
* ``HEADER``
* ``INT``
* ``IP``
* ``PROBE``
* ``REAL``
* ``STEVEDORE``
* ``STRANDS`` implicit via ``STRING``\ -folding
* ``STRING_LIST`` implicit via ``STRING``\ -folding
* ``STRING``
* ``TIME``
SYNOPSIS
========
Variable object construction is identical for all vmods from this
bundle, shown here by example of the ``int`` type, but the other types
mentioned above are supported likewise:
::
import constant [from "path"] ;
import globalvar [from "path"] ;
import taskvar [from "path"] ;
import topvar [from "path"] ;
vcl_init {
new xconst_int = constant.int(5);
new xglob_int = globalvar.int(5);
new xtask_int = taskvar.int(5);
new xtop_int = topvar.int(5);
}
All vmods support methods to ``.get()`` the value and check if the
variable is ``.defined()``.
All vmods except ``vmod_constant`` support ``.set()`` and
``.undefine()`` to assign a value to a variable or unset it.
``vmod_taskvar`` and ``vmod_topvar`` also support ``.protect()`` to
make a variable read-only for the rest of its lifetime and
``.protected()`` to check for protection status.
For details see the documentation of the individual vmods.
REQUIREMENTS
============
The VMOD requires the Varnish since version 6.0.0 or the master
branch. See the project repository for versions that are compatible
with other versions of Varnish.
INSTALLATION
============
See `INSTALL.rst <INSTALL.rst>`_ in the project source repository.
COPYRIGHT
=========
::
Copyright 2018 UPLEX Nils Goroll Systemoptimierung
All rights reserved
This document is licensed under the same conditions as the varnish-objvar
project. See LICENSE for details.
Author: Nils Goroll <nils.goroll@uplex.de>
......@@ -37,6 +37,47 @@ nodist_libvmod_topvar_la_SOURCES = \
@BUILD_VMOD_TASKVAR@
@BUILD_VMOD_TOPVAR@
VCCS = \
vmod_constant.vcc \
vmod_globalvar.vcc \
vmod_taskvar.vcc \
vmod_topvar.vcc
CS = \
vmod_constant.c \
vmod_globalvar.c \
vmod_taskvar.c \
vmod_topvar.c
TESTS = \
vtc/vmod_constant.vtc \
vtc/vmod_globalvar.vtc \
vtc/vmod_taskvar.vtc \
vtc/vmod_topvar.vtc
$(CS): type_magics.h type_cp.h tbl_types.h
vmod_taskvar.c: tasktop.h
vmod_topvar.c: tasktop.h
$(VCCS): $(top_srcdir)/LICENSE tbl_types.h
$(TESTS): tbl_vtc.h
.vcctpl.vcc:
@rm -f $<.h
@ln -s $< $<.h
$(AM_V_GEN) ( echo '#-' && \
sed < $(top_srcdir)/LICENSE 's:^:# :' && \
$(CPP) $<.h | sed '/^#/ d; s:\\n *:\n:g') >$@
@rm -f $<.h
.vtctpl.vtc:
@rm -f $<.h
@ln $< $<.h
$(AM_V_GEN) ($(CPP) $<.h | sed '/^#/ d; s:\\n *:\n:g; s: *%% *::g;') >$@
@rm -f $<.h
# Test suite
AM_TESTS_ENVIRONMENT = \
......@@ -48,19 +89,10 @@ AM_VTC_LOG_FLAGS = \
-p vcl_path="$(abs_top_srcdir)/vcl" \
-p vmod_path="$(abs_builddir)/.libs:$(vmoddir)"
TESTS = \
vtc/vmod_constant.vtc \
vtc/vmod_globalvar.vtc \
vtc/vmod_taskvar.vtc \
vtc/vmod_topvar.vtc
# Documentation
dist_doc_DATA = \
vmod_constant.vcc \
vmod_globalvar.vcc \
vmod_taskvar.vcc \
vmod_topvar.vcc \
$(VCCS) \
$(TESTS)
dist_man_MANS = \
......
/*-
* Copyright 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved.
*
* Author: Nils Goroll <nils.goroll@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define var_code(VMODPFX_, vmodpfx_, TYPE, type) \
struct vmodpfx_ ## type { \
uint16_t magic; \
int defined:1; \
int protected:1; \
VCL_ ## TYPE var; \
}; \
\
VCL_VOID \
vmod_ ## type ## __init(VRT_CTX, \
struct vmodpfx_ ## type **vp, \
const char *vcl_name, \
struct vmod_ ## type ##__init_arg *args) \
{ \
struct vmodpfx_ ## type *v; \
\
AN(vp); \
AZ(*vp); \
\
ALLOC_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
if (v == NULL) { \
VRT_fail(ctx, "%s: alloc failed", vcl_name); \
return; \
} \
\
if (args->valid_init) { \
CP_ ## TYPE (v->var, args->init); \
v->defined = 1; \
} \
*vp = v; \
} \
\
VCL_VOID \
vmod_ ## type ## __fini(struct vmodpfx_ ## type **vp) \
{ \
struct vmodpfx_ ## type *v = *vp; \
\
*vp = NULL; \
if (v == NULL) \
return; \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
FREE_ ## TYPE (v->var); \
FREE_OBJ(v); \
} \
\
VCL_ ## TYPE \
vmod_ ## type ## _get(VRT_CTX, struct vmodpfx_ ## type *va, \
VCL_ ## TYPE fallback) \
{ \
const struct vmodpfx_ ## type *v = state_r(ctx, va); \
\
if (v == NULL) \
return (fallback); \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
\
if (v->defined) \
return (v->var); \
\
return (fallback); \
} \
\
VCL_VOID \
vmod_ ## type ## _set(VRT_CTX, struct vmodpfx_ ## type *va, \
VCL_ ## TYPE val) \
{ \
struct vmodpfx_ ## type *v = \
state_l(ctx, va, sizeof *v); \
\
if (v == NULL) \
return; \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
\
if (v->protected) { \
VRT_fail(ctx, \
"attempt to set protected variable"); \
return; \
} \
\
if (v == va) \
CP_ ## TYPE (va->var, val); \
else \
v->var = val; \
\
v->defined = 1; \
} \
\
VCL_VOID \
vmod_ ## type ## _undefine(VRT_CTX, struct vmodpfx_ ## type *v) \
{ \
v = state_l(ctx, v, sizeof *v); \
\
if (v == NULL) \
return; \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
\
v->defined = 0; \
} \
\
VCL_BOOL \
vmod_ ## type ## _defined(VRT_CTX, struct vmodpfx_ ## type *va) \
{ \
const struct vmodpfx_ ## type *v = state_r(ctx, va); \
\
if (v == NULL) \
return (0); \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
\
return (!!v->defined); \
} \
VCL_VOID \
vmod_ ## type ## _protect(VRT_CTX, struct vmodpfx_ ## type *v) \
{ \
v = state_l(ctx, v, sizeof *v); \
\
if (v == NULL) \
return; \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
\
v->protected = 1; \
} \
\
VCL_BOOL \
vmod_ ## type ## _protected(VRT_CTX, \
struct vmodpfx_ ## type *va) \
{ \
const struct vmodpfx_ ## type *v = state_r(ctx, va); \
\
if (v == NULL) \
return (0); \
\
CHECK_OBJ(v, VMODPFX_ ## TYPE ## _MAGIC); \
\
return (!!v->protected); \
}
/* subset of tbl/vcc_types.h which we support */
/* standard text for defaults doc */
#define DEFDOC The default fallback is
#define DEF_ACL
#define DEFDOC_ACL
VCC_TYPE(ACL, acl)
#define DEF_BACKEND =0
#define DEFDOC_BACKEND DEFDOC no backend.
#define DEF_BACKEND =0
VCC_TYPE(BACKEND, backend)
#define DEF_BLOB
#define DEFDOC_BLOB
VCC_TYPE(BLOB, blob)
#define DEF_BODY
#define DEFDOC_BODY
VCC_TYPE(BODY, body)
#define DEF_BOOL
#define DEFDOC_BOOL
VCC_TYPE(BOOL, bool)
#define DEF_BYTES
#define DEFDOC_BYTES
VCC_TYPE(BYTES, bytes)
#define DEF_DURATION =0
#define DEFDOC_DURATION DEFDOC 0s.
VCC_TYPE(DURATION, duration)
// VCC_TYPE(ENUM, enum)
#define DEF_HEADER
#define DEFDOC_HEADER
VCC_TYPE(HEADER, header)
// VCC_TYPE(HTTP, http)
// VCC_TYPE(INSTANCE, instance)
#define DEF_INT =0
#define DEFDOC_INT DEFDOC 0.
VCC_TYPE(INT, int)
#define DEF_IP
#define DEFDOC_IP
VCC_TYPE(IP, ip)
#define DEF_PROBE
#define DEFDOC_PROBE
VCC_TYPE(PROBE, probe)
#define DEF_REAL =0.0
#define DEFDOC_REAL DEFDOC 0.0.
VCC_TYPE(REAL, real)
#define DEF_STEVEDORE
#define DEFDOC_STEVEDORE
VCC_TYPE(STEVEDORE, stevedore)
// VCC_TYPE(STRANDS)
#define DEF_STRING =0
#define DEFDOC_STRING DEFDOC the empty string.
VCC_TYPE(STRING, string)
// VCC_TYPE(STRINGS)
// VCC_TYPE(STRING_LIST)
// VCC_TYPE(SUB)
#define DEF_TIME =0
#define DEFDOC_TIME DEFDOC the epoch (1970/1/1 0:00:00 GMT).
VCC_TYPE(TIME, time)
// VCC_TYPE(VCL)
// VCC_TYPE(VOID)
#undef VCC_TYPE
/* subset of tbl/vcc_types.h which we can test */
#define VTC1_ACL acl1
#define VTC2_ACL acl2
#define CMP_ACL(a, b) a == b
VCC_TYPE(ACL, acl)
#define VTC1_BACKEND b1
#define VTC2_BACKEND b2
#define CMP_BACKEND(a, b) a == b
VCC_TYPE(BACKEND, backend)
#define VTC1_BLOB blob1.get()
#define VTC2_BLOB blob2.get()
#define CMP_BLOB(a, b) blob.equal(a, b)
VCC_TYPE(BLOB, blob)
// body support is very rudimentary
//#define VTC1_BODY
//#define VTC2_BODY
//VCC_TYPE(BODY, body)
// #2809 VCC bug for xx = bool1 == bool2
//#define VTC1_BOOL true
//#define VTC2_BOOL false
//#define CMP_BOOL(a, b) a == b
//VCC_TYPE(BOOL, bool)
#define VTC1_BYTES 1MB
#define VTC2_BYTES 2GB
#define CMP_BYTES(a, b) a == b
VCC_TYPE(BYTES, bytes)
#define VTC1_DURATION 1s
#define VTC2_DURATION 2h
#define CMP_DURATION(a, b) a == b
VCC_TYPE(DURATION, duration)
// VCC_TYPE(ENUM, enum)
// no way to get a header in vcl_init{}
//#define VTC1_HEADER
//#define VTC2_HEADER
//#define CMP_HEADER(a, b) a == b
//VCC_TYPE(HEADER, header)
// VCC_TYPE(HTTP, http)
// VCC_TYPE(INSTANCE, instance)
#define VTC1_INT 1
#define VTC2_INT 2
#define CMP_INT(a, b) a == b
VCC_TYPE(INT, int)
#define VTC1_IP "127.0.0.1"
#define VTC2_IP "127.0.0.2"
#define CMP_IP(a, b) a == b
VCC_TYPE(IP, ip)
#define VTC1_PROBE p1
#define VTC2_PROBE p2
#define CMP_PROBE(a, b) a == b
VCC_TYPE(PROBE, probe)
#define VTC1_REAL 1.1
#define VTC2_REAL 2.2
#define CMP_REAL(a, b) a == b
VCC_TYPE(REAL, real)
#define VTC1_STEVEDORE storage.stv1
#define VTC2_STEVEDORE storage.stv2
#define CMP_STEVEDORE(a, b) a == b
VCC_TYPE(STEVEDORE, stevedore)
// VCC_TYPE(STRANDS)
#define VTC1_STRING "1"
#define VTC2_STRING "2"
#define CMP_STRING(a, b) a == b
VCC_TYPE(STRING, string)
// VCC_TYPE(STRINGS)
// VCC_TYPE(STRING_LIST)
// VCC_TYPE(SUB)
#define VTC1_TIME now + 1h
#define VTC2_TIME now + 2h
#define CMP_TIME(a, b) (b - a < 10m)
VCC_TYPE(TIME, time)
// VCC_TYPE(VCL)
// VCC_TYPE(VOID)
#undef VCC_TYPE
/*-
* Copyright 2018 UPLEX Nils Goroll Systemoptimierung
* All rights reserved.
*
* Author: Nils Goroll <nils.goroll@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
const struct vmod_priv null_blob[1] = {{ 0 }};
/* based upon REPLACE() from miniobj.h */
#define cp_string(dst, src) \
do { \
char *d; \
if ((dst) != NULL) \
free(TRUST_ME(dst)); \
if ((src) != NULL) { \
d = strdup(src); \
AN(d); \
(dst) = d; \
} else { \
(dst) = NULL; \
} \
} while(0)
#define free_string(x) \
if (x) { \
free(TRUST_ME(x)); \
(x) = NULL; \
} \
(void)0
#define KIND_ACL immediate
#define CP_ACL(dst, src) (dst) = (src)
#define FREE_ACL(ptr) (void)0
#define KIND_BACKEND immediate
#define CP_BACKEND(dst, src) (dst) = (src)
#define FREE_BACKEND(ptr) (void)0
#define KIND_BLOB pointer
#define CP_BLOB(dst, src) \
do { \
struct vmod_priv *d; \
\
FREE_BLOB(dst); \
if ((src) == NULL || (src)->len == 0 || \
(src)->priv == NULL) { \
(dst) = null_blob; \
} else { \
d = malloc(sizeof *d); \
AN(d); \
d->priv = malloc((src)->len); \
AN(d->priv); \
memcpy(d->priv, (src)->priv, (src)->len); \
d->len = (src)->len; \
d->free = free; \
(dst) = d; \
} \
} while(0)
#define FREE_BLOB(ptr) \
if ((ptr) != NULL && (ptr) != null_blob) { \
VRT_priv_fini(ptr); \
free(TRUST_ME(ptr)); \
(ptr) = NULL; \
} \
(void)0
#define KIND_BODY pointer
#define CP_BODY(dst, src) cp_string(dst, src)
#define FREE_BODY(ptr) free_string(ptr)
#define KIND_BOOL immediate
#define CP_BOOL(dst, src) (dst) = (src)
#define FREE_BOOL(ptr) (void)0
#define KIND_BYTES immediate
#define CP_BYTES(dst, src) (dst) = (src)
#define FREE_BYTES(ptr) (void)0
#define KIND_DURATION immediate
#define CP_DURATION(dst, src) (dst) = (src)
#define FREE_DURATION(ptr) (void)0
#define KIND_HEADER pointer
#define CP_HEADER(dst, src) \
do { \
const struct gethdr_s *o = dst; \
struct gethdr_s *h; \
FREE_HEADER(o); \
AN(src); \
AN((src)->what); \
h = malloc(sizeof *h); \
AN(h); \
h->where = (src)->where; \
h->what = strdup((src)->what); \
AN(h->what); \
(dst) = h; \
} while(0)
#define FREE_HEADER(ptr) \
if ((ptr) != NULL) { \
if ((ptr)->what) \
free(TRUST_ME((ptr)->what)); \
free(TRUST_ME(ptr)); \
(ptr) = NULL; \
} \
(void)0
#define KIND_INT immediate
#define CP_INT(dst, src) (dst) = (src)
#define FREE_INT(ptr) (void)0
#define KIND_IP pointer
#define CP_IP(dst, src) \
do { \
struct suckaddr *d; \
FREE_IP(dst); \
d = malloc(vsa_suckaddr_len); \
AN(d); \
memcpy(d, (src), vsa_suckaddr_len); \
(dst) = d; \
} while(0)
#define FREE_IP(ptr) \
if ((ptr) != NULL) { \
free(TRUST_ME(ptr)); \
(ptr) = NULL; \
} \
(void)0
#define KIND_PROBE immediate
#define CP_PROBE(dst, src) (dst) = (src)
#define FREE_PROBE(ptr) (void)0
#define KIND_REAL immediate
#define CP_REAL(dst, src) (dst) = (src)
#define FREE_REAL(ptr) (void)0
#define KIND_STEVEDORE immediate
#define CP_STEVEDORE(dst, src) (dst) = (src)
#define FREE_STEVEDORE(ptr) (void)0
#define KIND_STRING pointer