...
 
......@@ -81,7 +81,14 @@ new xencoder = brotli.encoder(STRING name, BYTES bufffer)
XXX ...
# $Object decoder(STRING name, BYTES buffer=32k, BOOL lgwin=0)
.. _vmod_brotli.decoder:
new xdecoder = brotli.decoder(STRING name, BYTES buffer)
--------------------------------------------------------
::
new xdecoder = brotli.decoder(STRING name, BYTES buffer=32768)
XXX ...
......
......@@ -152,4 +152,8 @@ logexpect l1 -v v1 -d 1 -g vxid -q "VfpAcct" {
expect 0 * Begin bereq
expect * = VfpAcct {^unbr \d+ 843$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^unbr \d+ 119$}
expect * = End
} -run
# looks like -*- vcl -*-
varnishtest "brotli decompression with custom parameter settings"
# Test vectors from github.com/google/brotli/tests/testdata
server s1 {
rxreq
txresp -hdr "Content-Encoding: br" -hdr "Content-Length: 425"
sendhex "1b 4a 03 00 8c 94 6e de b4 d7 96 b1 78 86 f2 2d"
sendhex "e1 1a bc 0b 1c ba a9 c7 f7 cc 6e b2 42 34 51 44"
sendhex "8b 4e 13 08 a0 cd 6e e8 2c a5 53 a1 9c 5d 2c 1d"
sendhex "23 1a d2 56 be db eb 26 ba 03 65 7c 96 6a a2 76"
sendhex "ec ef 87 47 33 d6 27 0e 63 95 e2 1d 8d 2c c5 d1"
sendhex "28 9f 60 94 6f 02 8b dd aa 64 94 2c 1e 3b 65 7c"
sendhex "07 45 5a b2 e2 fc 49 81 2c 9f 40 ae ef 68 81 ac"
sendhex "16 7a 0f f5 3b 6d 1c b9 1e 2d 5f d5 c8 af 5e 85"
sendhex "aa 05 be 53 75 c2 b0 22 8a 15 c6 a3 b1 e6 42 14"
sendhex "f4 84 54 53 19 5f be c3 f2 1d d1 b7 e5 dd b6 d9"
sendhex "23 c6 f6 9f 9e f6 4d 65 30 fb c0 71 45 04 ad 03"
sendhex "b5 be c9 cb fd e2 50 5a 46 74 04 0d ff 20 04 77"
sendhex "b2 6d 27 bf 47 a9 9d 1b 96 2c 62 90 23 8b e0 f8"
sendhex "1d cf af 1d 3d ee 8a c8 75 23 66 dd de d6 6d e3"
sendhex "2a 82 8a 78 8a db e6 20 4c b7 5c 63 ba 30 e3 3f"
sendhex "b6 ee 8c 22 a2 2a b0 22 0a 99 ff 3d 62 51 ee 08"
sendhex "f6 3d 4a e4 cc ef 22 87 11 e2 83 28 e4 f5 8f 35"
sendhex "19 63 5b e1 5a 92 73 dd a1 50 9d 38 5c eb b5 03"
sendhex "6a 64 90 94 c8 8d fb 2f 8a 86 22 cc 1d 87 e0 48"
sendhex "0a 96 77 90 39 c6 23 23 48 fb 11 47 56 ca 20 e3"
sendhex "42 81 f7 77 32 c1 a5 5c 40 21 65 17 40 29 17 17"
sendhex "6c 56 32 98 38 06 dc 99 4d 33 29 bb 02 df 4c 26"
sendhex "93 6c 17 82 86 20 d7 03 79 7d 9a 00 d7 87 00 e7"
sendhex "0b 66 e3 4c 66 71 67 08 32 f9 08 3e 81 33 cd 17"
sendhex "72 31 f0 b8 94 52 4b 90 31 8e 68 c1 ef 90 c9 e5"
sendhex "f2 61 09 72 25 ad ec c5 62 c0 0b 12 05 f7 91 75"
sendhex "0d ee 61 2e 2e 19 09 c2 03"
rxreq
txresp -nolen -hdr "Content-Encoding: br" -hdr "Content-Length: 69"
sendhex "1b 76 00 00 14 4a ac 9b 7a bd e1 97 9d 7f 8e c2"
sendhex "82 36 0e 9c e0 90 03 f7 8b 9e 38 e6 b6 00 ab c3"
sendhex "ca a0 c2 da 66 36 dc cd 80 8d 2e 21 d7 6e e3 ea"
sendhex "4c b8 f0 d2 b8 c7 c2 70 4d 3a f0 69 7e a1 b8 45"
sendhex "73 ab c4 57 1e"
} -start
varnish v1 -arg "-p vsl_mask=+VfpAcct" -vcl+backend {
import ${vmod_brotli};
sub vcl_init {
new mybr = brotli.decoder("unbr1k", 1k);
}
sub vcl_backend_response {
set beresp.filters = "unbr1k";
set beresp.uncacheable = true;
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.Content-Encoding == <undef>
expect resp.bodylen == 843
expect resp.body == "znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmzxc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxcnzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqerioupqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyiowtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuriouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwotueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfhklasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfasdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjkaghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj"
txreq
rxresp
expect resp.status == 200
expect resp.http.Content-Encoding == <undef>
expect resp.bodylen == 119
expect resp.body == "ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies."
} -run
varnish v1 -vcl+backend {
import ${vmod_brotli};
sub vcl_init {
new mybr = brotli.decoder("unbr1m", 1m);
}
sub vcl_backend_response {
set beresp.filters = "unbr1m";
set beresp.uncacheable = true;
}
}
# Tests object finalization and DISCARD event.
varnish v1 -cli "vcl.discard vcl1"
varnish v1 -cli "vcl.list"
server s1 -wait
server s1 -start
client c1 -run
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name must be non-empty} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name br already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("br");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name unbr already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("unbr");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name esi already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("esi");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name esi_gzip already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("esi_gzip");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name gunzip already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("gunzip");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name gzip already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("gzip");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: filter name testgunzip already in use by another VFP} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("testgunzip");
}
}
varnish v1 -errvcl {vfp brotli failure: new mybr: buffer size must be > 0b} {
import ${vmod_brotli};
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new mybr = brotli.decoder("empty", 0b);
}
}
# Happens to be the same as the default decoder.
varnish v1 -vcl+backend {
import ${vmod_brotli};
sub vcl_init {
new mybr = brotli.decoder("unbr_default", 32k);
}
sub vcl_backend_response {
set beresp.filters = "unbr_default";
set beresp.uncacheable = true;
}
}
varnish v1 -cli "vcl.discard vcl2"
server s1 -wait
server s1 -start
client c1 -run
logexpect l1 -v v1 -d 1 -g vxid -q "VfpAcct" {
expect 0 * Begin bereq
expect * = VfpAcct {^unbr1k \d+ 843$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^unbr1k \d+ 119$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^unbr1m \d+ 843$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^unbr1m \d+ 119$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^unbr_default \d+ 843$}
expect * = End
expect 0 * Begin bereq
expect * = VfpAcct {^unbr_default \d+ 119$}
expect * = End
} -run
......@@ -86,6 +86,12 @@ struct vmod_brotli_encoder {
struct vfp *vfp;
};
struct vmod_brotli_decoder {
unsigned magic;
#define VMOD_BROTLI_DECODER_MAGIC 0x263b6d01
struct vfp *vfp;
};
struct custom_vfp_entry {
unsigned magic;
#define CUSTOM_VFP_MAGIC 0xfc88cb98
......@@ -502,28 +508,27 @@ vmod_event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
/* Object encoder */
VCL_VOID
vmod_encoder__init(VRT_CTX, struct vmod_brotli_encoder **encp,
const char *vcl_name, struct vmod_priv *priv,
VCL_STRING filter_name, VCL_BYTES bufsz)
static int
coder_init(VRT_CTX, const char *vcl_name, struct vmod_priv *priv,
VCL_STRING filter_name, VCL_BYTES bufsz, struct vfp **vfpp,
struct vbr_settings **settingsp)
{
struct vmod_brotli_encoder *enc;
struct vfp *vfp;
struct vbr_settings *settings;
struct custom_vfp_head *vfph;
struct custom_vfp_entry *vfpe;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(encp);
AZ(*encp);
AN(vcl_name);
AN(priv);
AN(filter_name);
AN(vfpp);
AN(settingsp);
assert(bufsz >= 0);
if (*filter_name == '\0') {
VFAIL(ctx, "new %s: filter name must be non-empty", vcl_name);
return;
return (-1);
}
if (strcmp(filter_name, "br") == 0 || strcmp(filter_name, "unbr") == 0
|| strcmp(filter_name, "esi") == 0
......@@ -534,19 +539,11 @@ vmod_encoder__init(VRT_CTX, struct vmod_brotli_encoder **encp,
VFAIL(ctx,
"new %s: filter name %s already in use by another VFP",
vcl_name, filter_name);
return;
return (-1);
}
if (bufsz == 0) {
VFAIL(ctx, "new %s: buffer size must be > 0b", vcl_name);
return;
}
errno = 0;
ALLOC_OBJ(enc, VMOD_BROTLI_ENCODER_MAGIC);
if (enc == NULL) {
VFAIL(ctx, "new %s: cannot allocate space for object: %s",
vcl_name, strerror(errno));
return;
return (-1);
}
errno = 0;
......@@ -554,39 +551,70 @@ vmod_encoder__init(VRT_CTX, struct vmod_brotli_encoder **encp,
if (vfp == NULL) {
VFAIL(ctx, "new %s: cannot allocate space for VFP: %s",
vcl_name, strerror(errno));
return;
return (-1);
}
*vfpp = vfp;
errno = 0;
ALLOC_OBJ(settings, VBR_SETTINGS_MAGIC);
if (vfp == NULL) {
if (settings == NULL) {
VFAIL(ctx, "new %s: cannot allocate space for settings: %s",
vcl_name, strerror(errno));
return;
return (-1);
}
*settingsp = settings;
errno = 0;
ALLOC_OBJ(vfpe, CUSTOM_VFP_MAGIC);
if (vfpe == NULL) {
VFAIL(ctx, "new %s: cannot allocate space VFP entry: %s",
VFAIL(ctx, "new %s: cannot allocate space for VFP list entry: %s",
vcl_name, strerror(errno));
return;
return (-1);
}
settings->bufsz = bufsz;
settings->which = ENC;
vfp->name = strdup(filter_name);
vfp->init = vfp_br_init;
vfp->pull = vfp_br_pull;
vfp->fini = vfp_br_fini;
vfp->priv1 = settings;
enc->vfp = vfp;
VRT_AddVFP(ctx, vfp);
vfph = init_priv_vcl(priv);
vfpe->vfp = vfp;
VSLIST_INSERT_HEAD(vfph, vfpe, list);
return (0);
}
VCL_VOID
vmod_encoder__init(VRT_CTX, struct vmod_brotli_encoder **encp,
const char *vcl_name, struct vmod_priv *priv,
VCL_STRING filter_name, VCL_BYTES bufsz)
{
struct vmod_brotli_encoder *enc;
struct vfp *vfp = NULL;
struct vbr_settings *settings = NULL;
AN(encp);
AZ(*encp);
if (coder_init(ctx, vcl_name, priv, filter_name, bufsz, &vfp,
&settings) != 0)
return;
AN(vfp);
CHECK_OBJ_NOTNULL(settings, VBR_SETTINGS_MAGIC);
errno = 0;
ALLOC_OBJ(enc, VMOD_BROTLI_ENCODER_MAGIC);
if (enc == NULL) {
VFAIL(ctx, "new %s: cannot allocate space for object: %s",
vcl_name, strerror(errno));
return;
}
vfp->pull = vfp_br_pull;
VRT_AddVFP(ctx, vfp);
settings->which = ENC;
enc->vfp = vfp;
}
/*
......@@ -607,6 +635,56 @@ vmod_encoder__fini(struct vmod_brotli_encoder **encp)
FREE_OBJ(enc);
}
/* Object decoder */
VCL_VOID
vmod_decoder__init(VRT_CTX, struct vmod_brotli_decoder **decp,
const char *vcl_name, struct vmod_priv *priv,
VCL_STRING filter_name, VCL_BYTES bufsz)
{
struct vmod_brotli_decoder *dec;
struct vfp *vfp = NULL;
struct vbr_settings *settings = NULL;
AN(decp);
AZ(*decp);
if (coder_init(ctx, vcl_name, priv, filter_name, bufsz, &vfp,
&settings) != 0)
return;
AN(vfp);
CHECK_OBJ_NOTNULL(settings, VBR_SETTINGS_MAGIC);
errno = 0;
ALLOC_OBJ(dec, VMOD_BROTLI_DECODER_MAGIC);
if (dec == NULL) {
VFAIL(ctx, "new %s: cannot allocate space for object: %s",
vcl_name, strerror(errno));
return;
}
vfp->pull = vfp_unbr_pull;
VRT_AddVFP(ctx, vfp);
settings->which = DEC;
dec->vfp = vfp;
}
/*
* As above, free the settings, custom VFP and PRIV_VCL list on DISCARD.
*/
VCL_VOID
vmod_decoder__fini(struct vmod_brotli_decoder **decp)
{
struct vmod_brotli_decoder *dec;
if (decp == NULL || *decp == NULL)
return;
CHECK_OBJ(*decp, VMOD_BROTLI_DECODER_MAGIC);
dec = *decp;
*decp = NULL;
FREE_OBJ(dec);
}
/* Version functions */
static VCL_STRING
......
......@@ -70,7 +70,7 @@ $Object encoder(PRIV_VCL, STRING name, BYTES bufffer=32768)
XXX ...
# $Object decoder(STRING name, BYTES buffer=32k, BOOL lgwin=0)
$Object decoder(PRIV_VCL, STRING name, BYTES buffer=32768)
XXX ...
......