Commit f0654041 authored by Geoff Simmons's avatar Geoff Simmons

Add the label object.

parent 35775ec4
Pipeline #353 skipped
......@@ -39,8 +39,36 @@ Varnish Module (VMOD) for dispatching control to VCL labels or subroutines.
CONTENTS
========
* label()
* STRING version()
.. _obj_label:
label
-----
::
new OBJ = label()
.. _func_label.add:
label.add
---------
::
VOID label.add(INT n, STRING label)
.. _func_label.go:
label.go
--------
::
VOID label.go(INT)
.. _func_version:
version
......
# looks like -*- vcl -*-
varnishtest "label object"
varnish v1 -vcl {
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
set req.http.VCL = "1";
return(synth(200));
}
sub vcl_synth {
set resp.http.VCL = req.http.VCL;
return(deliver);
}
} -start
varnish v1 -vcl {
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
set req.http.VCL = "2";
return(synth(200));
}
sub vcl_synth {
set resp.http.VCL = req.http.VCL;
return(deliver);
}
}
varnish v1 -cliok "vcl.label VCL1 vcl1"
varnish v1 -cliok "vcl.label VCL2 vcl2"
varnish v1 -vcl {
import ${vmod_dispatch};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new l = dispatch.label();
l.add(0, "VCL1");
l.add(1, "VCL2");
}
sub vcl_recv {
if (req.url == "/0") {
l.go(0);
}
if (req.url == "/1") {
l.go(1);
}
}
}
client c1 {
txreq -url "/0"
rxresp
expect resp.status == 200
expect resp.http.VCL == "1"
txreq -url "/1"
rxresp
expect resp.status == 200
expect resp.http.VCL == "2"
} -run
varnish v1 -cliok "vcl.list"
varnish v1 -errvcl {vmod dispatch error: l.add(-1, VCL1): n must be >= 0} {
import ${vmod_dispatch};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new l = dispatch.label();
l.add(-1, "VCL1");
}
}
varnish v1 -vcl {
import ${vmod_dispatch};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new l = dispatch.label();
l.add(0, "VCL1");
l.add(2, "VCL2");
}
sub vcl_recv {
if (req.url == "/negative") {
l.go(-1);
}
elsif (req.url == "/notset") {
l.go(1);
}
elsif (req.url == "/outofrange") {
l.go(3);
}
}
sub vcl_backend_fetch {
l.go(0);
}
}
client c1 {
txreq -url "/negative"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.VCL == <undef>
} -run
client c1 {
txreq -url "/notset"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.VCL == <undef>
} -run
client c1 {
txreq -url "/outofrange"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.VCL == <undef>
} -run
client c1 {
txreq
rxresp
expect resp.status == 503
expect resp.reason == "Service Unavailable"
expect resp.http.VCL == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * * VCL_Error "^vmod dispatch error: l.go.-1.: n must be >= 0$"
expect * * VCL_Error "^vmod dispatch error: l.go.1.: label 1 was not added$"
expect * * VCL_Error "^vmod dispatch error: l.go.3.: highest label number is 2"
expect * * VCL_Error "^vmod dispatch error: l.go.0.: may only be called in client context, not in any vcl_backend_. subroutine$"
} -start
logexpect l1 -wait
......@@ -26,12 +26,153 @@
* SUCH DAMAGE.
*/
/* for strdup() */
#define _POSIX_C_SOURCE 200809L
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "cache/cache.h"
#include "vcl.h"
#include "vbm.h"
#include "vcc_if.h"
#define ERR(ctx, msg) \
VRT_fail((ctx), "vmod dispatch error: " msg)
#define VERR(ctx, fmt, ...) \
VRT_fail((ctx), "vmod dispatch error: " fmt, __VA_ARGS__)
#define INIT_BITS (64)
struct vmod_dispatch_label {
unsigned magic;
#define VMOD_DISPATCH_LABEL_MAGIC 0x44515cd0
VCL_VCL *vcl;
struct vbitmap *bitmap;
char *vcl_name;
unsigned nvcls;
};
static struct vrt_ctx dummy_ctx = { .magic = VRT_CTX_MAGIC };
VCL_VOID
vmod_label__init(VRT_CTX, struct vmod_dispatch_label **labelp,
const char *vcl_name)
{
struct vmod_dispatch_label *label;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(labelp);
AZ(*labelp);
AN(vcl_name);
ALLOC_OBJ(label, VMOD_DISPATCH_LABEL_MAGIC);
AN(label);
*labelp = label;
label->bitmap = vbit_new(INIT_BITS);
AN(label->bitmap);
label->vcl_name = strdup(vcl_name);
AN(label->vcl_name);
AZ(label->vcl);
AZ(label->nvcls);
}
VCL_VOID
vmod_label__fini(struct vmod_dispatch_label **labelp)
{
struct vmod_dispatch_label *label;
if (labelp == NULL || *labelp == NULL)
return;
CHECK_OBJ(*labelp, VMOD_DISPATCH_LABEL_MAGIC);
label = *labelp;
*labelp = NULL;
for (unsigned i = 0; i < label->nvcls; i++)
if (vbit_test(label->bitmap, i) && label->vcl[i] != NULL)
VRT_vcl_rel(&dummy_ctx, label->vcl[i]);
if (label->bitmap != NULL)
vbit_destroy(label->bitmap);
if (label->vcl_name != NULL)
free(label->vcl_name);
FREE_OBJ(label);
}
VCL_VOID
vmod_label_add(VRT_CTX, struct vmod_dispatch_label *label, VCL_INT n,
VCL_STRING label_name)
{
VCL_VCL vcl;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(label, VMOD_DISPATCH_LABEL_MAGIC);
if ((ctx->method & VCL_MET_INIT) == 0) {
VERR(ctx, "%s.add(%ld, %s) may only be called in vcl_init",
label->vcl_name, n, label_name);
return;
}
if (n < 0) {
VERR(ctx, "%s.add(%ld, %s): n must be >= 0", label->vcl_name,
n, label_name);
return;
}
if ((vcl = VRT_vcl_get(ctx, label_name)) == NULL) {
/*
* XXX: currently doesn't work, VRT_vcl_get() internally
* has AN(vcl);
*/
VERR(ctx, "%s.add(%ld, %s): unknown label", label->vcl_name, n,
label_name);
return;
}
if (n >= label->nvcls)
label->nvcls = n + 1;
label->vcl = realloc(label->vcl, label->nvcls * sizeof(vcl));
if (label->vcl == NULL) {
VERR(ctx, "%s.add(%ld, %s): out of memory", label->vcl_name, n,
label_name);
return;
}
label->vcl[n] = vcl;
vbit_set(label->bitmap, n);
}
VCL_VOID
vmod_label_go(VRT_CTX, struct vmod_dispatch_label *label, VCL_INT n)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(label, VMOD_DISPATCH_LABEL_MAGIC);
if (ctx->req == NULL) {
VERR(ctx, "%s.go(%ld): may only be called in client context, "
"not in any vcl_backend_* subroutine", label->vcl_name,
n);
return;
}
if (n < 0) {
VERR(ctx, "%s.go(%ld): n must be >= 0", label->vcl_name, n);
return;
}
if (n >= label->nvcls) {
VERR(ctx, "%s.go(%ld): highest label number is %d",
label->vcl_name, n, label->nvcls - 1);
return;
}
if (!vbit_test(label->bitmap, n)) {
VERR(ctx, "%s.go(%ld): label %ld was not added",
label->vcl_name, n, n);
return;
}
VRT_vcl_select(ctx, label->vcl[n]);
VRT_handling(ctx, VCL_RET_VCL);
}
VCL_STRING
vmod_version(const struct vrt_ctx *ctx)
vmod_version(VRT_CTX)
{
(void) ctx;
return VERSION;
......
......@@ -21,6 +21,12 @@ Varnish Module (VMOD) for dispatching control to VCL labels or subroutines.
... XXX ...
$Object label()
$Method VOID .add(INT n, STRING label)
$Method VOID .go(INT)
$Function STRING version()
Return the version string for this VMOD.
......
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