Commit 6c711bfa authored by Geoff Simmons's avatar Geoff Simmons

Add documentation.

parent 44f02bdd
......@@ -7,7 +7,7 @@
.. role:: ref(emphasis)
=============
vmod_dispatch
VMOD dispatch
=============
-------------------------------------------------------------------
......@@ -19,95 +19,255 @@ Varnish Module for dispatching control to VCL labels or subroutines
SYNOPSIS
========
.. parsed-literal::
import dispatch [from "path"]
new xlabel = dispatch.label()
VOID xlabel.add(INT n, STRING label)
VOID xlabel.go(INT)
STRING xlabel.string(INT)
new xsub = dispatch.sub()
VOID xsub.add(INT n, STRING sub)
VOID xsub.call(INT n)
STRING xsub.string(INT)
STRING version()
::
import dispatch;
# Labels
new <obj> = dispatch.label()
VOID <obj>.add(INT n, STRING label)
VOID <obj>.go(INT)
STRING <obj>.string(INT)
# Subroutines
new <obj> = dispatch.sub()
VOID <obj>.add(INT n, STRING sub)
VOID <obj>.call(INT)
STRING <obj>.string(INT)
# VMOD version
STRING dispatch.version()
DESCRIPTION
===========
Varnish Module (VMOD) for dispatching control to VCL labels or subroutines.
... XXX ...
Varnish Module (VMOD) for dispatching control to VCL labels or
subroutines. Both the ``label`` and ``sub`` objects have an
``.add()`` method used in ``vcl_init``, to assign an integer to a
label or subroutine. The integer can then be used in the
``label.go(INT)`` method to branch to the corresponding label, or in
``sub.call(INT)`` to call the subroutine.
See ``varnish-cli(7)`` and ``vcl(7)`` for details about VCL labels and
subroutines.
Examples::
# Assign 0 to VCL label mylabel.
sub vcl_init {
new labelobj = dispatch.label();
# The string in .add() must match the label name.
labelobj.add(0, "mylabel");
}
sub vcl_recv {
if (req.url == "/label0") {
labelobj.go(0);
}
}
# Assign 1 to VCL subroutine sub1
sub vcl_init {
new subobj = dispatch.sub();
# The string in .add() must match the VCL symbol for the
# subroutine.
subobj.add(1, "sub1");
}
sub sub1 {
std.log("VCL subroutine sub1 called");
}
sub vcl_recv {
if (req.url == "/call1") {
subobj.call(1);
}
}
.. _vmod_dispatch.label:
new xlabel = dispatch.label()
-----------------------------
Initialize a ``label`` object.
Example::
sub vcl_init {
new labels = dispatch.label();
# ... add assignments as shown below.
}
.. _vmod_dispatch.label.add:
VOID xlabel.add(INT n, STRING label)
------------------------------------
Assign ``n`` to the VCL label whose symbolic name matches the string
``label``.
The ``.add()`` method MUST NOT be called in any VCL subroutine besides
``vcl_init``. ``n`` MUST NOT be less than zero, and the string
``label`` MUST be identical to a VCL label name.
Example::
sub vcl_init {
new labels = dispatch.label();
labels.add(0, "foo_label");
}
.. _vmod_dispatch.label.go:
VOID xlabel.go(INT)
-------------------
Branch to the label that was assigned to the integer argument by the
``.add()`` method.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``. The label branching MUST be legal as in standard Varnish,
which means that:
* ``.go()`` MUST NOT be invoked in backend context (in any
``vcl_backend_*`` subroutine), since label branching is only
permitted in client context.
* ``.go()`` MUST NOT be invoked after control has already branched to
a label, since branching from label to label is not permitted.
Example::
import std;
sub vcl_recv {
# For URLs beginng with /l0/, /l1/, etc., branch to label N,
# where N is the integer in the URL prefix.
if (req.url ~ "^/l\d+/") {
labels.go(std.integer(
regsub(req.url, "^/l(\d+)/.*", "\1")));
}
}
.. _vmod_dispatch.label.string:
STRING xlabel.string(INT)
-------------------------
Return the name of the label that was assigned to the integer argument
by ``.add()``.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``.
Example::
import std;
sub vcl_hit {
if (req.url ~ "^/l\d+/") {
std.log("Cache hit in label "
+ labels.string(std.integer(
regsub(req.url, "^/l(\d+)/.*", "\1"))))
}
}
.. _vmod_dispatch.sub:
new xsub = dispatch.sub()
-------------------------
Initialize a ``sub`` object.
Example::
sub vcl_init {
new subs = dispatch.sub();
# ... add assignments as shown below.
}
.. _vmod_dispatch.sub.add:
VOID xsub.add(INT n, STRING sub)
--------------------------------
Assign ``n`` to the VCL subroutine whose symbolic name matches the
string ``sub``.
The ``.add()`` method MUST NOT be called in any VCL subroutine besides
``vcl_init``. ``n`` MUST NOT be less than zero, and the string ``sub``
MUST be identical to a user-defined VCL subroutine name. ``.add()``
MAY NOT be used to assign one of the standard VCL subroutines (with
the ``vcl_`` prefix).
Example::
import std;
sub vcl_init {
new subs = dispatch.sub();
subs.add(0, "foo_sub");
}
sub foo_sub {
std.log("Subroutine foo_sub was invoked");
}
.. _vmod_dispatch.sub.call:
VOID xsub.call(INT n)
---------------------
Call the subroutine that was assigned to the integer argument by the
``.add()`` method.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``. The subroutine call MUST be legal as in standard
Varnish, which means that:
* The subroutine invoked by ``.call()`` MUST be legal in the context
in which it is invoked. The backend or client context of the called
subroutine MUST match the context in which it is called. If the
subroutine uses variables or other VCL constructs that are only
legal under certain VCL subroutines, then it MUST be invoked in the
context of one of those subroutines.
See ``vcl(7)`` for details about the legal use of VCL subroutines.
Example::
import std;
sub vcl_backend_response {
# If the backend response has header Type with an an integer
# value, call the subroutine assigned to that integer.
if (beresp.http.Type ~ "^\d+$") {
subs.call(std.integer(
regsub(beresp.http.Type, "(\d+)", "\1")));
}
}
.. _vmod_dispatch.sub.string:
STRING xsub.string(INT)
-----------------------
Return the name of the VCL subroutine that was assigned to the integer
argument by ``.add()``.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``.
Example::
import std;
if (beresp.http.Type ~ "^\d+$") {
std.log("Called in subroutine "
+ subs.string(std.integer(
regsub(beresp.http.Type, "(\d+)", "\1"))));
}
}
.. _vmod_dispatch.version:
......@@ -123,9 +283,12 @@ Example::
REQUIREMENTS
============
The VMOD requires the Varnish master branch. See the source repository
for versions of the VMOD that are compatible with other Varnish
versions.
The VMOD requires Varnish since version 6.0.0.
The VMOD is built with strict ABI compatibility, meaning that it MUST
be run against exactly the same version of Varnish against which it
was built -- the version strings must be identical, including the
revision string (the source repository commit ID).
INSTALLATION
============
......@@ -135,7 +298,95 @@ See `INSTALL.rst <INSTALL.rst>`_ in the source repository.
LIMITATIONS
===========
... XXX ...
For the standard use of VCL labels and subroutines, Varnish has a
number of compile-time and runtime checks to ensure their
correctness. Among these are:
* The symbols used for a label or subroutine are defined -- a label
has been defined with the ``vcl.label`` command (see
``varnish-cli(7)``), and a subroutine is defined elsewhere in the
VCL source.
* Label branching is only permitted in client context, and you may not
branch to a label after having already branched to a label.
* If a subroutine uses VCL variables or other language constructs that
may only be used in the context of certain VCL subroutines, Varinsh
ensures at compile-time that their usage is legal (by checking the
possible call stacks in which the subroutine is invoked via
``call``). See ``vcl(7)``.
* Varnish checks at compile-time if a VCL subroutine is used properly
in client or backend context.
* Varnish checks at compile-time if a VCL subroutine that is defined
is also invoked somewhere via ``call``. By default, the VCL load
fails if a defined subroutine is never called (this helps prevent
errors due to misspellings, for example). The failure can be relaxed
to a warning by setting the ``varnishd`` parameter ``vcc_err_unref``
to ``off`` (see ``varnishd(1)``).
The VMOD can check some of these constraints:
* The ``sub.add()`` method fails if the subroutine named by its string
argument is not defined.
* The ``label.go()`` method fails if it is not invoked in client
context.
For these and other errors defined in this document, VCL failure is
invoked. If the error occurs in ``vcl_init``, then the VCL load fails
with an error message from the VMOD. If it occurs in any other VCL
subroutine, a synthetic "503 VCL failed" response is generated, and
the VMOD error message is written to the log.
The VMOD *cannot* check for the following violations -- the results
are undefined, and Varnish is likely to crash:
* An undefined label is named in ``label.add()``.
* ``label.go()`` is invoked after a label has already been entered.
* The subroutine called by ``sub.call()`` is not legal in the context
in which it is invoked -- it is invoked in client context where
backend context is required, or vice versa; or it uses VCL language
constructs that are not legal in its invocation context.
It is therefore imperative to carefully review and test your use of
the VMOD to ensure that these rules are never broken.
If you define subroutines that are only ever invoked via
``sub.call()``, then the compile-time "unref" check will identify them
as unused, and the VCL load will fail unless ``vcc_err_unref`` is set
to ``off``.
If you prefer to keep the "unref" check, for example to suppress
warnings and have the compiler check your use of other subroutines, it
is possible (although a bit ugly) to write ``call`` statements for
them in VCL code that is never executed::
sub vcl_recv {
# ...
# The following subroutines are "actually" called only via
# sub.call(). The calls in this if statement are never
# executed, but since the subroutines are mentioned here, they
# are not identified by the compile-time "unref" check.
if (false) {
call sub1;
call sub2;
call sub3;
}
}
Internally, the VMOD uses tables indexed by the integers used in the
``.add()``, ``.go()`` and ``.call()`` methods. The tables are
allocated to be large enough for the largest such integer for each
VMOD object. It is therefore highly advisable to use small integers,
ideally just 0 to `N-1` if you are defining `N` labels or subroutines
for an object. If, for example, your objects use only the values 998,
999 and 1000, then space is allocated for about 1000 entries, almost
all of which is wasted memory.
AUTHOR
======
......@@ -149,6 +400,7 @@ SEE ALSO
* varnishd(1)
* vcl(7)
* varnish-cli(7)
* VMOD source repository: https://code.uplex.de/uplex-varnish/libvmod-dispatch
COPYRIGHT
......
......@@ -9,34 +9,237 @@
$Module dispatch 3 "Varnish Module for dispatching control to VCL labels or subroutines"
$Synopsis manual
SYNOPSIS
========
::
import dispatch;
# Labels
new <obj> = dispatch.label()
VOID <obj>.add(INT n, STRING label)
VOID <obj>.go(INT)
STRING <obj>.string(INT)
# Subroutines
new <obj> = dispatch.sub()
VOID <obj>.add(INT n, STRING sub)
VOID <obj>.call(INT)
STRING <obj>.string(INT)
# VMOD version
STRING dispatch.version()
DESCRIPTION
===========
Varnish Module (VMOD) for dispatching control to VCL labels or subroutines.
Varnish Module (VMOD) for dispatching control to VCL labels or
subroutines. Both the ``label`` and ``sub`` objects have an
``.add()`` method used in ``vcl_init``, to assign an integer to a
label or subroutine. The integer can then be used in the
``label.go(INT)`` method to branch to the corresponding label, or in
``sub.call(INT)`` to call the subroutine.
See ``varnish-cli(7)`` and ``vcl(7)`` for details about VCL labels and
subroutines.
Examples::
# Assign 0 to VCL label mylabel.
sub vcl_init {
new labelobj = dispatch.label();
# The string in .add() must match the label name.
labelobj.add(0, "mylabel");
}
sub vcl_recv {
if (req.url == "/label0") {
labelobj.go(0);
}
}
... XXX ...
# Assign 1 to VCL subroutine sub1
sub vcl_init {
new subobj = dispatch.sub();
# The string in .add() must match the VCL symbol for the
# subroutine.
subobj.add(1, "sub1");
}
sub sub1 {
std.log("VCL subroutine sub1 called");
}
sub vcl_recv {
if (req.url == "/call1") {
subobj.call(1);
}
}
$Object label()
Initialize a ``label`` object.
Example::
sub vcl_init {
new labels = dispatch.label();
# ... add assignments as shown below.
}
$Method VOID .add(INT n, STRING label)
Assign ``n`` to the VCL label whose symbolic name matches the string
``label``.
The ``.add()`` method MUST NOT be called in any VCL subroutine besides
``vcl_init``. ``n`` MUST NOT be less than zero, and the string
``label`` MUST be identical to a VCL label name.
Example::
sub vcl_init {
new labels = dispatch.label();
labels.add(0, "foo_label");
}
$Method VOID .go(INT)
Branch to the label that was assigned to the integer argument by the
``.add()`` method.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``. The label branching MUST be legal as in standard Varnish,
which means that:
* ``.go()`` MUST NOT be invoked in backend context (in any
``vcl_backend_*`` subroutine), since label branching is only
permitted in client context.
* ``.go()`` MUST NOT be invoked after control has already branched to
a label, since branching from label to label is not permitted.
Example::
import std;
sub vcl_recv {
# For URLs beginng with /l0/, /l1/, etc., branch to label N,
# where N is the integer in the URL prefix.
if (req.url ~ "^/l\d+/") {
labels.go(std.integer(
regsub(req.url, "^/l(\d+)/.*", "\1")));
}
}
$Method STRING .string(INT)
Return the name of the label that was assigned to the integer argument
by ``.add()``.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``.
Example::
import std;
sub vcl_hit {
if (req.url ~ "^/l\d+/") {
std.log("Cache hit in label "
+ labels.string(std.integer(
regsub(req.url, "^/l(\d+)/.*", "\1"))))
}
}
$Object sub()
Initialize a ``sub`` object.
Example::
sub vcl_init {
new subs = dispatch.sub();
# ... add assignments as shown below.
}
$Method VOID .add(INT n, STRING sub)
Assign ``n`` to the VCL subroutine whose symbolic name matches the
string ``sub``.
The ``.add()`` method MUST NOT be called in any VCL subroutine besides
``vcl_init``. ``n`` MUST NOT be less than zero, and the string ``sub``
MUST be identical to a user-defined VCL subroutine name. ``.add()``
MAY NOT be used to assign one of the standard VCL subroutines (with
the ``vcl_`` prefix).
Example::
import std;
sub vcl_init {
new subs = dispatch.sub();
subs.add(0, "foo_sub");
}
sub foo_sub {
std.log("Subroutine foo_sub was invoked");
}
$Method VOID .call(INT n)
Call the subroutine that was assigned to the integer argument by the
``.add()`` method.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``. The subroutine call MUST be legal as in standard
Varnish, which means that:
* The subroutine invoked by ``.call()`` MUST be legal in the context
in which it is invoked. The backend or client context of the called
subroutine MUST match the context in which it is called. If the
subroutine uses variables or other VCL constructs that are only
legal under certain VCL subroutines, then it MUST be invoked in the
context of one of those subroutines.
See ``vcl(7)`` for details about the legal use of VCL subroutines.
Example::
import std;
sub vcl_backend_response {
# If the backend response has header Type with an an integer
# value, call the subroutine assigned to that integer.
if (beresp.http.Type ~ "^\d+$") {
subs.call(std.integer(
regsub(beresp.http.Type, "(\d+)", "\1")));
}
}
$Method STRING .string(INT)
Return the name of the VCL subroutine that was assigned to the integer
argument by ``.add()``.
The argument MUST be one of the numbers assigned by ``.add()`` in
``vcl_init``.
Example::
import std;
if (beresp.http.Type ~ "^\d+$") {
std.log("Called in subroutine "
+ subs.string(std.integer(
regsub(beresp.http.Type, "(\d+)", "\1"))));
}
}
$Function STRING version()
Return the version string for this VMOD.
......@@ -48,9 +251,12 @@ Example::
REQUIREMENTS
============
The VMOD requires the Varnish master branch. See the source repository
for versions of the VMOD that are compatible with other Varnish
versions.
The VMOD requires Varnish since version 6.0.0.
The VMOD is built with strict ABI compatibility, meaning that it MUST
be run against exactly the same version of Varnish against which it
was built -- the version strings must be identical, including the
revision string (the source repository commit ID).
INSTALLATION
============
......@@ -60,7 +266,95 @@ See `INSTALL.rst <INSTALL.rst>`_ in the source repository.
LIMITATIONS
===========
... XXX ...
For the standard use of VCL labels and subroutines, Varnish has a
number of compile-time and runtime checks to ensure their
correctness. Among these are:
* The symbols used for a label or subroutine are defined -- a label
has been defined with the ``vcl.label`` command (see
``varnish-cli(7)``), and a subroutine is defined elsewhere in the
VCL source.
* Label branching is only permitted in client context, and you may not
branch to a label after having already branched to a label.
* If a subroutine uses VCL variables or other language constructs that
may only be used in the context of certain VCL subroutines, Varinsh
ensures at compile-time that their usage is legal (by checking the
possible call stacks in which the subroutine is invoked via
``call``). See ``vcl(7)``.
* Varnish checks at compile-time if a VCL subroutine is used properly
in client or backend context.
* Varnish checks at compile-time if a VCL subroutine that is defined
is also invoked somewhere via ``call``. By default, the VCL load
fails if a defined subroutine is never called (this helps prevent
errors due to misspellings, for example). The failure can be relaxed
to a warning by setting the ``varnishd`` parameter ``vcc_err_unref``
to ``off`` (see ``varnishd(1)``).
The VMOD can check some of these constraints:
* The ``sub.add()`` method fails if the subroutine named by its string
argument is not defined.
* The ``label.go()`` method fails if it is not invoked in client
context.
For these and other errors defined in this document, VCL failure is
invoked. If the error occurs in ``vcl_init``, then the VCL load fails
with an error message from the VMOD. If it occurs in any other VCL
subroutine, a synthetic "503 VCL failed" response is generated, and
the VMOD error message is written to the log.
The VMOD *cannot* check for the following violations -- the results
are undefined, and Varnish is likely to crash:
* An undefined label is named in ``label.add()``.
* ``label.go()`` is invoked after a label has already been entered.
* The subroutine called by ``sub.call()`` is not legal in the context
in which it is invoked -- it is invoked in client context where
backend context is required, or vice versa; or it uses VCL language
constructs that are not legal in its invocation context.
It is therefore imperative to carefully review and test your use of
the VMOD to ensure that these rules are never broken.
If you define subroutines that are only ever invoked via
``sub.call()``, then the compile-time "unref" check will identify them
as unused, and the VCL load will fail unless ``vcc_err_unref`` is set
to ``off``.
If you prefer to keep the "unref" check, for example to suppress
warnings and have the compiler check your use of other subroutines, it
is possible (although a bit ugly) to write ``call`` statements for
them in VCL code that is never executed::
sub vcl_recv {
# ...
# The following subroutines are "actually" called only via
# sub.call(). The calls in this if statement are never
# executed, but since the subroutines are mentioned here, they
# are not identified by the compile-time "unref" check.
if (false) {
call sub1;
call sub2;
call sub3;
}
}
Internally, the VMOD uses tables indexed by the integers used in the
``.add()``, ``.go()`` and ``.call()`` methods. The tables are
allocated to be large enough for the largest such integer for each
VMOD object. It is therefore highly advisable to use small integers,
ideally just 0 to `N-1` if you are defining `N` labels or subroutines
for an object. If, for example, your objects use only the values 998,
999 and 1000, then space is allocated for about 1000 entries, almost
all of which is wasted memory.
AUTHOR
======
......@@ -74,4 +368,5 @@ SEE ALSO
* varnishd(1)
* vcl(7)
* varnish-cli(7)
* VMOD source repository: https://code.uplex.de/uplex-varnish/libvmod-dispatch
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