Commit 60cc5f9b authored by Geoff Simmons's avatar Geoff Simmons

Add VMOD blob.

References #2402
parent 2c41d0de
varnishtest "VMOD blob vcl.use and .discard"
server s1 {
} -start
varnish v1 -vcl+backend {
import blob;
} -start
varnish v1 -vcl+backend {
}
varnish v1 -cli "vcl.list"
varnish v1 -cli "vcl.use vcl1"
varnish v1 -cli "vcl.use vcl2"
varnish v1 -cli "vcl.use vcl1"
varnish v1 -expect vmods == 1
varnish v1 -cli "vcl.show vcl1"
varnish v1 -cli "vcl.use vcl2"
varnish v1 -cli "vcl.discard vcl1"
varnish v1 -cli "vcl.list"
varnish v1 -expect vmods == 0
varnishtest "VMOD blob IDENTITY encode and decode"
varnish v1 -vcl {
import blob;
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.id =
blob.encode(IDENTITY, blob.decode(IDENTITY,
"The quick brown fox jumps over the lazy dog"));
set resp.http.hobbes =
blob.encode(IDENTITY, blob.decode(IDENTITY,
{"Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."}));
set resp.http.list =
blob.encode(IDENTITY, blob.decode(IDENTITY,
"" + req.http.unset + req.url +
"The quick brown fox jumps over " +
req.http.unset + "" + req.http.unset + "" +
"the lazy dog" + req.url + req.http.unset + ""));
set resp.http.empty =
blob.encode(IDENTITY, blob.decode(IDENTITY, ""));
set resp.http.undef =
blob.encode(IDENTITY, blob.decode(IDENTITY,
req.http.unset));
set resp.http.emptylist =
blob.encode(IDENTITY, blob.decode(IDENTITY,
req.http.unset + "" + req.http.unset + ""));
set resp.http.param =
blob.encode(blob=
blob.decode(encoded=
"The quick brown fox jumps over the lazy dog",
decoding=IDENTITY),
encoding=IDENTITY);
set resp.http.paramlist =
blob.encode(IDENTITY, blob.decode(encoded=
"" + req.http.unset + req.url +
"The quick brown fox jumps over " +
req.http.unset + "" + req.http.unset + "" +
"the lazy dog" + req.url + req.http.unset + "",
decoding=IDENTITY));
set resp.http.truncated =
blob.encode(IDENTITY, blob.decode(HEX, "666f6f00626172"));
}
} -start
client c1 {
txreq -url "/"
rxresp
expect resp.http.id == "The quick brown fox jumps over the lazy dog"
expect resp.http.hobbes == "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."
expect resp.http.list == "/The quick brown fox jumps over the lazy dog/"
expect resp.http.empty == ""
expect resp.http.undef == ""
expect resp.http.emptylist == ""
expect resp.http.param == "The quick brown fox jumps over the lazy dog"
expect resp.http.paramlist == "/The quick brown fox jumps over the lazy dog/"
expect resp.http.truncated == "foo"
} -run
varnishtest "VMOD blob IDENTITY decode_n()"
varnish v1 -vcl {
import blob;
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.id =
blob.encode(IDENTITY, blob.decode_n(5, IDENTITY,
"The quick brown fox jumps over the lazy dog"));
set resp.http.hobbes =
blob.encode(IDENTITY, blob.decode_n(5, IDENTITY,
{"Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."}));
set resp.http.list =
blob.encode(IDENTITY, blob.decode_n(6, IDENTITY,
"" + req.http.unset + req.url +
"The quick brown fox jumps over " +
req.http.unset + "" + req.http.unset + "" +
"the lazy dog" + req.url + req.http.unset + ""));
set resp.http.empty =
blob.encode(IDENTITY, blob.decode_n(5, IDENTITY, ""));
set resp.http.undef =
blob.encode(IDENTITY, blob.decode_n(5, IDENTITY,
req.http.unset));
set resp.http.emptylist =
blob.encode(IDENTITY, blob.decode_n(5, IDENTITY,
req.http.unset + "" + req.http.unset + ""));
set resp.http.param =
blob.encode(blob=
blob.decode_n(encoded=
"The quick brown fox jumps over the lazy dog",
n=7, decoding=IDENTITY),
encoding=IDENTITY);
set resp.http.paramlist =
blob.encode(IDENTITY, blob.decode_n(encoded=
"" + req.http.unset + req.url +
"The quick brown fox jumps over " +
req.http.unset + "" + req.http.unset + "" +
"the lazy dog" + req.url + req.http.unset + "",
decoding=IDENTITY, n=37));
}
} -start
client c1 {
txreq -url "/"
rxresp
expect resp.http.id == "The q"
expect resp.http.hobbes == "Man i"
expect resp.http.list == "/The q"
expect resp.http.empty == ""
expect resp.http.undef == ""
expect resp.http.emptylist == ""
expect resp.http.param == "The qui"
expect resp.http.paramlist == "/The quick brown fox jumps over the l"
} -run
This diff is collapsed.
varnishtest "VMOD blob hex decode_n()"
varnish v1 -vcl {
import blob;
import std;
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set req.http.pangram = "The quick brown fox jumps over the lazy dog";
set req.http.hobbes =
{"Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."};
# base64 encoding of all 256 byte values in ascending order
set req.http.b64all =
{"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="};
set resp.http.hexlc =
blob.encode(HEXLC,
blob.decode_n(5, IDENTITY, req.http.pangram));
set resp.http.hexuc =
blob.encode(HEXUC,
blob.decode_n(5, IDENTITY, req.http.pangram));
set resp.http.hobbeslc =
blob.encode(HEXLC, blob.decode_n(5, IDENTITY, req.http.hobbes));
set resp.http.hobbesuc =
blob.encode(HEXUC, blob.decode_n(5, IDENTITY, req.http.hobbes));
set resp.http.all-lc =
blob.encode(HEXLC, blob.decode_n(8, BASE64, req.http.b64all));
set resp.http.all-uc =
blob.encode(HEXUC, blob.decode_n(8, BASE64, req.http.b64all));
set resp.http.empty-lc =
blob.encode(HEXLC, blob.decode_n(5, IDENTITY, ""));
set resp.http.empty-uc =
blob.encode(HEXUC, blob.decode_n(5, IDENTITY, ""));
set resp.http.hexlcparam =
blob.encode(blob=blob.decode_n(5, IDENTITY, req.http.pangram),
encoding=HEXLC);
set resp.http.hexucparam =
blob.encode(blob=blob.decode_n(5, IDENTITY, req.http.pangram),
encoding=HEXUC);
set req.http.hexucfoobar = "666F6F206261722062617A2071757578";
set req.http.hexlcfoobar = std.tolower(req.http.hexucfoobar);
# Hobbes quotation in hex
set req.http.hexhobbeslc = "4d616e2069732064697374696e677569736865642c206e6f74206f6e6c792062792068697320726561736f6e2c2062757420627920746869732073696e67756c61722070617373696f6e2066726f6d206f7468657220616e696d616c732c2077686963682069732061206c757374206f6620746865206d696e642c20746861742062792061207065727365766572616e6365206f662064656c6967687420696e2074686520636f6e74696e75656420616e6420696e6465666174696761626c652067656e65726174696f6e206f66206b6e6f776c656467652c2065786365656473207468652073686f727420766568656d656e6365206f6620616e79206361726e616c20706c6561737572652e";
set req.http.hexhobbesuc = std.toupper(req.http.hexhobbeslc);
set req.http.hexalluc = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
set req.http.hexalllc = std.tolower(req.http.hexalluc);
set req.http.hexallucodd = regsub(req.http.hexalluc, "^0", "");
set req.http.hexalllcodd = regsub(req.http.hexalllc, "^0", "");
set resp.http.decuc =
blob.encode(IDENTITY,
blob.decode_n(10, HEX, req.http.hexucfoobar));
set resp.http.declc =
blob.encode(IDENTITY,
blob.decode_n(10, HEX, req.http.hexlcfoobar));
set resp.http.dechobbesuc =
blob.encode(IDENTITY,
blob.decode_n(12, HEX, req.http.hexhobbesuc));
set resp.http.dechobbeslc =
blob.encode(IDENTITY,
blob.decode_n(12, HEX, req.http.hexhobbeslc));
set resp.http.decalluc =
blob.encode(BASE64, blob.decode_n(12, HEX, req.http.hexalluc));
set resp.http.decalllc =
blob.encode(BASE64, blob.decode_n(12, HEX, req.http.hexalllc));
set resp.http.decallucodd =
blob.encode(BASE64, blob.decode_n(11, HEX,
req.http.hexallucodd));
set resp.http.decalllcodd =
blob.encode(BASE64, blob.decode_n(11, HEX,
req.http.hexalllcodd));
set resp.http.decempty =
blob.encode(IDENTITY, blob.decode_n(5, HEX, ""));
set resp.http.decemptybyte =
blob.encode(IDENTITY, blob.decode_n(1, HEX, "00"));
set resp.http.decemptynibble =
blob.encode(IDENTITY, blob.decode_n(2, HEX, "0"));
set resp.http.decemptypieces =
blob.encode(IDENTITY,
blob.decode_n(5, HEX, req.http.unset + ""
+ req.http.unset + ""));
set req.http.part1 = "666";
set resp.http.dec2pieces =
blob.encode(IDENTITY, blob.decode_n(6, HEX, req.http.part1 +
"F6F206261722062617A2071757578"));
set req.http.part2 = "57578";
set resp.http.dec3param =
blob.encode(blob=blob.decode_n(encoded=req.http.part1 +
"F6F206261722062617A20717" + req.http.part2,
decoding=HEX,n=8),
encoding=IDENTITY);
set resp.http.dec3pieces =
blob.encode(IDENTITY, blob.decode_n(30, HEX, req.http.part1 +
"F6F206261722062617A20717" + req.http.part2));
set resp.http.decmanypieces =
blob.encode(IDENTITY, blob.decode_n(20, HEX, "" + req.http.unset
+ req.http.part1 + req.http.unset + ""
+ req.http.unset + "" + "F6F206261722062617A20717"
+ "" + req.http.unset + req.http.part2
+ req.http.unset + "" + req.http.unset));
}
} -start
client c1 {
txreq -url "/"
rxresp
expect resp.http.hexlc == "5468652071"
expect resp.http.hexuc == "5468652071"
expect resp.http.hobbeslc == "4d616e2069"
expect resp.http.hobbesuc == "4D616E2069"
expect resp.http.all-uc == "000102030405"
expect resp.http.all-lc == "000102030405"
expect resp.http.empty-uc == ""
expect resp.http.empty-lc == ""
expect resp.http.hexlcparam == "5468652071"
expect resp.http.hexucparam == "5468652071"
expect resp.http.decuc == "foo b"
expect resp.http.declc == "foo b"
expect resp.http.dechobbesuc == "Man is"
expect resp.http.dechobbeslc == "Man is"
expect resp.http.decalluc == "AAECAwQF"
expect resp.http.decalllc == "AAECAwQF"
expect resp.http.decallucodd == "AAECAwQF"
expect resp.http.decalllcodd == "AAECAwQF"
expect resp.http.decempty == ""
expect resp.http.decemptybyte == ""
expect resp.http.decemptynibble == ""
expect resp.http.decemptypieces == ""
expect resp.http.dec2pieces == "foo"
expect resp.http.dec3pieces == "foo bar baz quu"
expect resp.http.dec3param == "foo "
expect resp.http.decmanypieces == "foo bar ba"
} -run
# Decode failure
server s1 {
rxreq
txresp
} -start
varnish v1 -vcl+backend {
import blob;
sub vcl_deliver {
set req.http.foo = "123";
set resp.http.badhex = blob.encode(HEXUC,
blob.decode_n(2, HEX, "g" + req.http.foo));
}
}
client c1 {
txreq
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.badhex == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod blob error: cannot decode, illegal encoding beginning with \"g\"$"
#"
expect * = End
} -start
logexpect l1 -wait
This diff is collapsed.
varnishtest "VMOD blob base64 decode_n()"
varnish v1 -vcl {
import blob;
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set req.http.foobarbazquux = "L0hlbGxvIHdvcmxkLw==";
set req.http.pangram
= "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==";
set req.http.hobbes =
{"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="};
set req.http.hobbesnopad = regsuball(req.http.hobbes, "=", "");
set req.http.all =
{"AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZaaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzz0000111122223333444455556666777788889999++++////"};
set req.http.allurl =
{"AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZaaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzz0000111122223333444455556666777788889999----____"};
set resp.http.dec
= blob.encode(IDENTITY,
blob.decode_n(8, BASE64,
req.http.foobarbazquux));
set resp.http.deceq
= blob.encode(IDENTITY,
blob.decode_n(20, BASE64,
req.http.foobarbazquux));
set resp.http.declong
= blob.encode(IDENTITY,
blob.decode_n(30, BASE64,
req.http.foobarbazquux));
set resp.http.dec2
= blob.encode(IDENTITY,
blob.decode_n(12, BASE64, req.http.pangram));
set resp.http.b64dechobbes =
blob.encode(IDENTITY,
blob.decode_n(24, BASE64, req.http.hobbes));
set resp.http.b64decall =
blob.encode(HEXLC, blob.decode_n(128, BASE64,
req.http.all));
set resp.http.urldechobbes =
blob.encode(IDENTITY, blob.decode_n(180, BASE64URL,
req.http.hobbes));
set resp.http.urldecall =
blob.encode(HEXLC,
blob.decode_n(256, BASE64URL,
req.http.allurl));
set resp.http.nopaddechobbes =
blob.encode(IDENTITY,
blob.decode_n(500, BASE64URLNOPAD,
req.http.hobbesnopad));
set resp.http.nopaddecall =
blob.encode(HEXLC,
blob.decode_n(256, BASE64URLNOPAD,
req.http.allurl));
set resp.http.b64empty =
blob.encode(IDENTITY, blob.decode_n(0, BASE64, ""));
set resp.http.urlempty =
blob.encode(IDENTITY, blob.decode_n(1, BASE64URL, ""));
set resp.http.nopadempty =
blob.encode(IDENTITY,
blob.decode_n(0, BASE64URLNOPAD, ""));
set resp.http.emptypieces =
blob.encode(IDENTITY,
blob.decode_n(0, BASE64, req.http.unset + "" + req.http.unset
+ "" + req.http.unset + ""));
set resp.http.decenc
= blob.encode(BASE64,
blob.decode_n(20, BASE64,
req.http.foobarbazquux));
set resp.http.l = "L";
set resp.http.dec2pieces
= blob.encode(IDENTITY, blob.decode_n(8, BASE64,
resp.http.l + "0hlbGxvIHdvcmxkLw=="));
set resp.http.pad = "==";
set resp.http.dec3pieces
= blob.encode(IDENTITY, blob.decode_n(12, BASE64,
resp.http.l + "0hlbGxvIHdvcmxkLw"
+ resp.http.pad));
set resp.http.mid1 = "GxvI";
set resp.http.mid2 = "dvcmx";
set resp.http.dec7pieces
= blob.encode(IDENTITY, blob.decode_n(16, BASE64,
resp.http.l + "0hlb" + resp.http.mid1
+ "H" + resp.http.mid2 + "kLw"
+ resp.http.pad));
set resp.http.dec7param
= blob.encode(blob=blob.decode_n(encoded=resp.http.l
+ "0hlb" + resp.http.mid1 + "H" + resp.http.mid2
+ "kLw" + resp.http.pad, decoding=BASE64, n=20),
encoding=IDENTITY);
set resp.http.decnopad = blob.encode(IDENTITY,
blob.decode_n(18, BASE64URLNOPAD,
"L0hlbGxvIHdvcmxkLw"));
set resp.http.decnopad2pieces
= blob.encode(IDENTITY, blob.decode_n(19, BASE64URLNOPAD,
resp.http.l + "0hlbGxvIHdvcmxkLw"));
set resp.http.decnopad6pieces
= blob.encode(IDENTITY, blob.decode_n(18, BASE64URLNOPAD,
resp.http.l + "0hlb" + resp.http.mid1
+ "H" + resp.http.mid2 + "kLw"));
set resp.http.decnopadlong
= blob.encode(IDENTITY,
blob.decode_n(60, BASE64URLNOPAD,
"VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw"
));
}
} -start
client c1 {
txreq -url "/"
rxresp
expect resp.http.dec == "/Hello"
expect resp.http.deceq == "/Hello world/"
expect resp.http.declong == "/Hello world/"
expect resp.http.dec2 == "The quick"
expect resp.http.b64dechobbes == "Man is distinguish"
expect resp.http.b64decall == "0000000410410820820c30c31041041451451861861c71c720820824924928a28a2cb2cb30c30c34d34d38e38e3cf3cf4104104514514924924d34d35145145555555965965d75d761861865965969a69a6db6db71c71c75d75d79e79e7df7df"
expect resp.http.urldechobbes == "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a p"
expect resp.http.urldecall == "0000000410410820820c30c31041041451451861861c71c720820824924928a28a2cb2cb30c30c34d34d38e38e3cf3cf4104104514514924924d34d35145145555555965965d75d761861865965969a69a6db6db71c71c75d75d79e79e7df7df8208208618618a28a28e38e39249249659659a69a69e79e7a28a28a69a69aaaaaaaebaebb2cb2cb6db6dbaebaebefbefc30c30c71c71cb2cb2cf3cf3d34d34d75d75db6db6df7df7e38e38e79e79ebaebaefbefbf3cf3cf7df7dfbefbeffffff"
expect resp.http.nopaddechobbes == "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."
expect resp.http.nopaddecall == "0000000410410820820c30c31041041451451861861c71c720820824924928a28a2cb2cb30c30c34d34d38e38e3cf3cf4104104514514924924d34d35145145555555965965d75d761861865965969a69a6db6db71c71c75d75d79e79e7df7df8208208618618a28a28e38e39249249659659a69a69e79e7a28a28a69a69aaaaaaaebaebb2cb2cb6db6dbaebaebefbefc30c30c71c71cb2cb2cf3cf3d34d34d75d75db6db6df7df7e38e38e79e79ebaebaefbefbf3cf3cf7df7dfbefbeffffff"
expect resp.http.b64empty == ""
expect resp.http.urlempty == ""
expect resp.http.nopadempty == ""
expect resp.http.emptypieces == ""
expect resp.http.decenc == "L0hlbGxvIHdvcmxkLw=="
expect resp.http.dec2pieces == "/Hello"
expect resp.http.dec3pieces == "/Hello wo"
expect resp.http.dec7pieces == "/Hello world"
expect resp.http.dec7param == "/Hello world/"
expect resp.http.decnopad == "/Hello world/"
expect resp.http.decnopad2pieces == "/Hello world/"
expect resp.http.decnopad6pieces == "/Hello world/"
expect resp.http.decnopadlong == "The quick brown fox jumps over the lazy dog"
} -run
# Decode failures
server s1 -repeat 3 {
rxreq
txresp
} -start
varnish v1 -vcl+backend {
import blob;
sub vcl_deliver {
set req.http.foo = "AAA=";
if (req.url == "/base64") {
set resp.http.bad64 = blob.encode(IDENTITY,
blob.decode_n(8, BASE64, "-_-_" + req.http.foo));
}
elsif (req.url == "/base64url") {
set resp.http.badurl = blob.encode(IDENTITY,
blob.decode_n(8, BASE64URL, "+/+/" + req.http.foo));
}
elsif (req.url == "/base64urlnopad") {
set resp.http.badpad = blob.encode(IDENTITY,
blob.decode_n(8, BASE64URLNOPAD,
"TWFu" + req.http.foo));
}
}
}
client c1 {
txreq -url /base64
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.bad64 == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * * VCL_Error {^vmod blob error: cannot decode, illegal encoding beginning with "-_-_"$}
} -start
logexpect l1 -wait
client c1 {
txreq -url /base64url
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.badurl == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * * VCL_Error {^vmod blob error: cannot decode, illegal encoding beginning with "././"$}
} -start
logexpect l1 -wait
client c1 {
txreq -url /base64urlnopad
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.badpad == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * * VCL_Error {^vmod blob error: cannot decode, illegal encoding beginning with "TWFu"$}
} -start
logexpect l1 -wait
This diff is collapsed.
varnishtest "VMOD blob decode_n() with URL"
varnish v1 -vcl {
import blob;
import std;
backend b { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set req.http.urllcfoobar = "foo%3abar%3abaz%3aquux";
set req.http.urlucfoobar = "foo%3Abar%3Abaz%3Aquux";
set req.http.urlhobbeslc = "Man%20is%20distinguished%2c%20not%20only%20by%20his%20reason%2c%20but%20by%20this%20singular%20passion%20from%20other%20animals%2c%20which%20is%20a%20lust%20of%20the%20mind%2c%20that%20by%20a%20perseverance%20of%20delight%20in%20the%20continued%20and%20indefatigable%20generation%20of%20knowledge%2c%20exceeds%20the%20short%20vehemence%20of%20any%20carnal%20pleasure.";
set req.http.urlhobbesuc = "Man%20is%20distinguished%2C%20not%20only%20by%20his%20reason%2C%20but%20by%20this%20singular%20passion%20from%20other%20animals%2C%20which%20is%20a%20lust%20of%20the%20mind%2C%20that%20by%20a%20perseverance%20of%20delight%20in%20the%20continued%20and%20indefatigable%20generation%20of%20knowledge%2C%20exceeds%20the%20short%20vehemence%20of%20any%20carnal%20pleasure.";
set req.http.urllcumlauts = "%c3%9cbergr%c3%b6%c3%9fentr%c3%a4ger";
set req.http.urlucumlauts = "%C3%9Cbergr%C3%B6%C3%9Fentr%C3%A4ger";
set req.http.urllcphk = "sm%c3%a5b%c3%b8rnsp%c3%a6dagog";
set req.http.urlucphk = "sm%C3%A5b%C3%B8rnsp%C3%A6dagog";
set req.http.urllcutf8 = "%e6%97%a5%e6%89%bc%e8%aa%9e";
set req.http.urlucutf8 = "%E6%97%A5%E6%89%BC%E8%AA%9E";
set req.http.urlalluc = "%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF";
set req.http.urlalllc = "%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f%20%21%22%23%24%25%26%27%28%29%2a%2b%2c-.%2f0123456789%3a%3b%3c%3d%3e%3f%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5b%5c%5d%5e_%60abcdefghijklmnopqrstuvwxyz%7b%7c%7d~%7f%80%81%82%83%84%85%86%87%88%89%8a%8b%8c%8d%8e%8f%90%91%92%93%94%95%96%97%98%99%9a%9b%9c%9d%9e%9f%a0%a1%a2%a3%a4%a5%a6%a7%a8%a9%aa%ab%ac%ad%ae%af%b0%b1%b2%b3%b4%b5%b6%b7%b8%b9%ba%bb%bc%bd%be%bf%c0%c1%c2%c3%c4%c5%c6%c7%c8%c9%ca%cb%cc%cd%ce%cf%d0%d1%d2%d3%d4%d5%d6%d7%d8%d9%da%db%dc%dd%de%df%e0%e1%e2%e3%e4%e5%e6%e7%e8%e9%ea%eb%ec%ed%ee%ef%f0%f1%f2%f3%f4%f5%f6%f7%f8%f9%fa%fb%fc%fd%fe%ff";
set resp.http.decuc =
blob.encode(IDENTITY,
blob.decode_n(9, URL, req.http.urlucfoobar));
set resp.http.declc =
blob.encode(IDENTITY,
blob.decode_n(12, URL, req.http.urllcfoobar));
set resp.http.dechobbesuc =
blob.encode(IDENTITY,
blob.decode_n(27, URL, req.http.urlhobbesuc));
set resp.http.dechobbeslc =
blob.encode(IDENTITY,
blob.decode_n(27, URL, req.http.urlhobbeslc));
set resp.http.decumlautsuc =
blob.encode(IDENTITY,
blob.decode_n(17, URL,
req.http.urlucumlauts));
set resp.http.decumlautslc =
blob.encode(IDENTITY,
blob.decode_n(25, URL,
req.http.urllcumlauts));
set resp.http.decphkuc =
blob.encode(IDENTITY,
blob.decode_n(18, URL, req.http.urlucphk));
set resp.http.decphklc =
blob.encode(IDENTITY,
blob.decode_n(30, URL, req.http.urllcphk));
set resp.http.decutf8uc =
blob.encode(IDENTITY,
blob.decode_n(9, URL, req.http.urlucutf8));
set resp.http.decutf8lc =
blob.encode(IDENTITY,
blob.decode_n(18, URL, req.http.urllcutf8));
set resp.http.decalluc =
blob.encode(HEXLC,
blob.decode_n(252, URL, req.http.urlalluc));
set resp.http.decalllc =
blob.encode(HEXUC,
blob.decode_n(252, URL, req.http.urlalllc));
set resp.http.decempty =
blob.encode(IDENTITY, blob.decode_n(10, URL, ""));
set resp.http.decemptybyte =
blob.encode(IDENTITY, blob.decode_n(3, URL, "%00"));
set resp.http.decemptypieces =
blob.encode(IDENTITY,
blob.decode_n(1, URL, req.http.unset + ""
+ req.http.unset + ""));
set req.http.part1 = "foo%";
set resp.http.dec2pieces =
blob.encode(IDENTITY,
blob.decode_n(6, URL, req.http.part1 +
"20bar%20baz%20quux"));
set req.http.part2 = "0quux";
set resp.http.dec3param =
blob.encode(blob=blob.decode_n(encoded=req.http.part1 +
"20bar%20baz%2" + req.http.part2,
decoding=URL, n=12),
encoding=IDENTITY);
set resp.http.dec3pieces =
blob.encode(IDENTITY,
blob.decode_n(18, URL, req.http.part1
+ "20bar%20baz%2"
+ req.http.part2));
set resp.http.decmanypieces =
blob.encode(IDENTITY,
blob.decode_n(24, URL, "" + req.http.unset
+ req.http.part1 + req.http.unset + ""
+ req.http.unset + "" + "20bar%20baz%2"
+ "" + req.http.unset + req.http.part2
+ req.http.unset + "" + req.http.unset));
}
} -start
client c1 {
txreq
rxresp
expect resp.http.decuc == "foo:bar"
expect resp.http.declc == "foo:bar:"
expect resp.http.dechobbesuc == "Man is distinguished,"
expect resp.http.dechobbeslc == "Man is distinguished,"
expect resp.http.decumlautsuc == "Übergrö"
expect resp.http.decumlautslc == "Übergrößen"
expect resp.http.decphkuc == "småbørns"
expect resp.http.decphklc == "småbørnspædagog"
expect resp.http.decutf8uc == "日"
expect resp.http.decutf8lc == "日扼"
expect resp.http.decalluc == "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
expect resp.http.decalllc == "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"
expect resp.http.decempty == ""
expect resp.http.decemptybyte == ""
expect resp.http.decemptypieces == ""
expect resp.http.dec2pieces == "foo "
expect resp.http.dec3pieces == "foo bar baz "
expect resp.http.dec3param == "foo bar "
expect resp.http.decmanypieces == "foo bar baz quux"
} -run
# Decode failures
server s1 -repeat 4 {
rxreq
txresp
} -start
varnish v1 -vcl+backend {
import blob;
sub vcl_deliver {
if (req.url == "/percent") {
set resp.http.bad = blob.encode(URLUC,
blob.decode_n(1, URL, "%20"));
}
elsif (req.url == "/percent-two") {
set resp.http.bad = blob.encode(URLUC,
blob.decode_n(2, URL, "%20"));
}
elsif (req.url == "/comma") {
set resp.http.good = blob.encode(IDENTITY,
blob.decode_n(3, URL, "%2c%q"));
}
elsif (req.url == "/colon") {
set resp.http.good = blob.encode(IDENTITY,
blob.decode_n(3, URL, "%3a%2q"));
}
}
}
client c1 {
txreq -url /comma
rxresp
expect resp.status == 200
expect resp.http.good == ","
txreq -url /colon
rxresp
expect resp.status == 200
expect resp.http.good == ":"
txreq -url /percent
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.bad == <undef>
} -run
client c1 {
txreq -url /percent-two
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect resp.http.bad == <undef>
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect * * VCL_Error "^vmod blob error: cannot decode, illegal encoding beginning with \"%20\"$"
expect * * VCL_Error "^vmod blob error: cannot decode, illegal encoding beginning with \"%20\"$"
} -run
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
varnishtest "VMOD blob test all examples from the vcc/rst"
server s1 {
rxreq
txresp
} -start
varnish v1 -arg "-p http_max_hdr=128" -vcl+backend {
import blob;
import std;
############################################################
# top Usage section
sub vcl_init {
# Create blob objects from encodings such as base64 or hex.
new myblob = blob.blob(BASE64, "Zm9vYmFy");
new yourblob = blob.blob(encoded="666F6F", decoding=HEX);
}
sub vcl_deliver {
# The .get() method retrieves the BLOB from an object.
set resp.http.MyBlob-As-Hex
= blob.encode(blob=myblob.get(), encoding=HEXLC);
# The .encode() method efficiently retrieves an encoding.
set resp.http.YourBlob-As-Base64 = yourblob.encode(BASE64);
# decode() and encode() functions convert blobs to text and
# vice versa at runtime.
set resp.http.Base64-Encoded
= blob.encode(BASE64,
blob.decode(HEX, req.http.Hex-Encoded));
}
sub vcl_recv {
# transcode() converts from one encoding to another.
set req.http.Hex-Encoded
= blob.transcode(decoding=BASE64, encoding=HEXUC, encoded="YmF6");
# transcode() can replace other specific encoding/deconding
# vmods - e.g. vmod_urlcode
set req.url = blob.transcode(encoded=req.url, decoding=URL);
set req.http.url_urlcoded
= blob.transcode(encoded=req.url, encoding=URLLC);
}
# get output from recv
sub vcl_deliver {
set resp.http.url_urlcoded = req.http.url_urlcoded;
}
############################################################
# IDENTITY
sub vcl_deliver {
set resp.http.Trunced-Foo1
= blob.encode(IDENTITY, blob.decode(HEX, "666f6f00626172"));
set resp.http.Trunced-Foo2
= blob.encode(blob=blob.decode(HEX, "666f6f00626172"));
}
############################################################
# HEX
sub vcl_deliver {
set resp.http.First = "abc";
set resp.http.Second = "def0";
set resp.http.Hex-Decoded = blob.encode(
HEXLC,
blob.decode(HEX, resp.http.First + resp.http.Second));
}
############################################################
# encode - also contains decode examples
sub vcl_deliver {
set resp.http.encode1
= blob.encode(HEXLC, blob.decode(BASE64, "Zm9vYmFyYmF6"));
# same with named parameters
set resp.http.encode2
= blob.encode(blob=blob.decode(encoded="Zm9vYmFyYmF6",
decoding=BASE64),
encoding=HEXLC);
# convert blob to string
set resp.http.encode3
= blob.encode(blob=blob.decode(encoded="foo"));
}
############################################################
# transcode
sub vcl_deliver {
set resp.http.Hex2Base64-1 = blob.transcode(HEX, BASE64, "666f6f");
# same with named parameters
set resp.http.Hex2Base64-2
= blob.transcode(encoded="666f6f",
encoding=BASE64, decoding=HEX);
# replacement for urlcode.decode("foo%20bar")
set resp.http.urldecoded
= blob.transcode(encoded="foo%20bar", decoding=URL);
# replacement for urlcode.encode("foo bar")
set resp.http.urlencoded
= blob.transcode(encoded="foo bar", encoding=URLLC);
}
############################################################
# blob init + .get + .encode
sub vcl_init {
new theblob1 = blob.blob(BASE64, "YmxvYg==");
# same with named arguments
new theblob2 = blob.blob(encoded="YmxvYg==", decoding=BASE64);
# string as a blob
new stringblob = blob.blob(encoded="bazz");
}
sub vcl_deliver {
# .get
set resp.http.The-Blob1 =
blob.encode(blob=theblob1.get());
set resp.http.The-Blob2 =
blob.encode(blob=theblob2.get());
set resp.http.The-Stringblob =
blob.encode(blob=stringblob.get());
# .encode
# blob as text
set resp.http.The-Blob = theblob1.encode();
# blob as base64
set resp.http.The-Blob-b64 = theblob1.encode(BASE64);
}
} -start
client c1 {
txreq -url "/foo%20bar"
rxresp
expect resp.status == 200
expect resp.http.MyBlob-As-Hex == "666f6f626172"
expect resp.http.YourBlob-As-Base64 == "Zm9v"
expect resp.http.Base64-Encoded == "YmF6"
expect resp.http.url_urlcoded == "%2ffoo%20bar"
expect resp.http.Trunced-Foo1 == "foo"
expect resp.http.Trunced-Foo2 == "foo"
expect resp.http.First == "abc"
expect resp.http.Second == "def0"
expect resp.http.Hex-Decoded == "0abcdef0"
expect resp.http.encode1 == "666f6f62617262617a"
expect resp.http.encode2 == "666f6f62617262617a"
expect resp.http.encode3 == "foo"
expect resp.http.Hex2Base64-1 == "Zm9v"
expect resp.http.Hex2Base64-2 == "Zm9v"
expect resp.http.urldecoded == "foo bar"
expect resp.http.urlencoded == "foo%20bar"
expect resp.http.The-Blob1 == "blob"
expect resp.http.The-Blob2 == "blob"
expect resp.http.The-Stringblob == "bazz"
expect resp.http.The-Blob == "blob"
expect resp.http.The-Blob-b64 == "YmxvYg=="
} -run
......@@ -32,3 +32,4 @@ VTC_VMOD(debug)
VTC_VMOD(directors)
VTC_VMOD(purge)
VTC_VMOD(vtc)
VTC_VMOD(blob)
......@@ -734,6 +734,7 @@ AC_CONFIG_FILES([
lib/libvmod_directors/Makefile
lib/libvmod_purge/Makefile
lib/libvmod_vtc/Makefile
lib/libvmod_blob/Makefile
man/Makefile
varnishapi.pc
varnishapi-uninstalled.pc
......
......@@ -213,6 +213,10 @@ reference/vmod_vtc.generated.rst: reference $(top_builddir)/lib/libvmod_vtc/vmod
cp $(top_builddir)/lib/libvmod_vtc/vmod_vtc.rst $@ || true
BUILT_SOURCES += reference/vmod_vtc.generated.rst
reference/vmod_blob.generated.rst: reference $(top_builddir)/lib/libvmod_blob/vmod_blob.rst
cp $(top_builddir)/lib/libvmod_blob/vmod_blob.rst $@ || true
BUILT_SOURCES += reference/vmod_blob.generated.rst
EXTRA_DIST += $(BUILT_SOURCES)
MAINTAINERCLEANFILES = $(EXTRA_DIST)
......
......@@ -24,6 +24,7 @@ The Varnish Reference Manual
vmod_directors.generated.rst
vmod_vtc.generated.rst
vmod_purge.generated.rst
vmod_blob.generated.rst
directors.rst
varnish-counters.rst
vsl.rst
......
......@@ -9,4 +9,5 @@ SUBDIRS = \
libvmod_std \
libvmod_directors \
libvmod_purge \
libvmod_vtc
libvmod_vtc \
libvmod_blob
#
AM_LDFLAGS = $(AM_LT_LDFLAGS)
AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/bin/varnishd \
-I$(top_builddir)/include
vmoddir = $(pkglibdir)/vmods
vmod_srcdir = $(top_srcdir)/lib/libvmod_blob
vmodtool = $(top_srcdir)/lib/libvcc/vmodtool.py
vmodtoolargs = --strict
vmod_LTLIBRARIES = libvmod_blob.la
libvmod_blob_la_CFLAGS = \
@SAN_CFLAGS@
libvmod_blob_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-version -shared \
@SAN_LDFLAGS@
libvmod_blob_la_SOURCES = \
vmod_blob.c \
vmod_blob.h \
id.c \
base64.h \
base64.c \
hex.h \
hex.c \
url.c \
wb.h \
wb.c \
parse_encoding.h \
parse_encoding.c
nodist_libvmod_blob_la_SOURCES = \
vcc_if.c \
vcc_if.h
# BUILT_SOURCES is only a hack and dependency tracking does not help for the first build
$(libvmod_blob_la_OBJECTS):vcc_if.h
vcc_if.h vmod_blob.rst vmod_blob.man.rst: vcc_if.c
vcc_if.c: $(vmodtool) $(vmod_srcdir)/vmod.vcc
@PYTHON@ $(vmodtool) $(vmodtoolargs) $(vmod_srcdir)/vmod.vcc
base64.o: base64.c base64.h
EXTRA_DIST = vmod.vcc
CLEANFILES = $(builddir)/vcc_if.c $(builddir)/vcc_if.h \
$(builddir)/vmod_blob.rst \
$(builddir)/vmod_blob.man.rst
/*-
* Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include "config.h"
#include <errno.h>
#include <stdint.h>
#include "base64.h"
#include "vdef.h"
#include "vrt.h"
#include "vas.h"
#define base64_l(l) (((l) << 2) / 3)
size_t
base64nopad_encode_l(size_t l)
{
return base64_l(l) + 4;
}
size_t
base64_encode_l(size_t l)
{
return (((base64_l(l)) + 3) & ~3) + 1;
}
size_t
base64_decode_l(size_t l)
{
return ((l) * 3) >> 2;
}
static inline int
decode(char *restrict *restrict dest, char *restrict const buf,
const size_t buflen, unsigned u, const int n)
{
char *d;
if (n <= 1) {
errno = EINVAL;
return -1;
}
d = *dest;
for (int i = 0; i < n - 1; i++) {
if (d == buf + buflen) {
errno = ENOMEM;
return -1;
}
*d++ = (u >> 16) & 0xff;
u <<= 8;
}
*dest += d - *dest;
return 1;
}
ssize_t
base64_encode(const enum encoding enc, char *restrict const buf,
const size_t buflen, const char *restrict const inbuf,
const size_t inlength)
{
const struct b64_alphabet *alpha = &b64_alphabet[enc];
char *p = buf;
const uint8_t *in = (const uint8_t *)inbuf;
const uint8_t * const end = in + inlength;
AN(buf);
AN(alpha);
if (in == NULL || inlength == 0)
return 0;
if ((enc == BASE64URLNOPAD &&
buflen < base64nopad_encode_l(inlength)) ||
(enc != BASE64URLNOPAD &&
buflen < base64_encode_l(inlength))) {
errno = ENOMEM;
return -1;
}
while (end - in >= 3) {
*p++ = alpha->b64[(in[0] >> 2) & 0x3f];
*p++ = alpha->b64[((in[0] << 4) | (in[1] >> 4)) & 0x3f];
*p++ = alpha->b64[((in[1] << 2) | (in[2] >> 6)) & 0x3f];
*p++ = alpha->b64[in[2] & 0x3f];
in += 3;
}
if (end - in > 0) {
*p++ = alpha->b64[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
*p++ = alpha->b64[(in[0] << 4) & 0x3f];
if (alpha->padding) {
*p++ = alpha->padding;
*p++ = alpha->padding;
}
}
else {
*p++ = alpha->b64[((in[0] << 4) | (in[1] >> 4)) & 0x3f];
*p++ = alpha->b64[(in[1] << 2) & 0x3f];
if (alpha->padding) {
*p++ = alpha->padding;
}
}
}
assert(p >= buf && p - buf <= buflen);
return p - buf;
}
ssize_t
base64_decode(const enum encoding dec, char *restrict const buf,
const size_t buflen, ssize_t inlen,
const char *const p, va_list ap)
{
const struct b64_alphabet *alpha = &b64_alphabet[dec];
char *dest = buf;
unsigned u = 0, term = 0;
int n = 0;
size_t len = SIZE_MAX;
AN(buf);
AN(alpha);
if (inlen >= 0)
len = inlen;
for (const char *s = p; len > 0 && s != vrt_magic_string_end;
s = va_arg(ap, const char *)) {
if (s == NULL)
continue;
if (*s && term) {
errno = EINVAL;
return -1;
}
while (*s && len) {
while (n < 4) {
char b = alpha->i64[(unsigned) *s++];
u <<= 6;
if (b == ILL) {
errno = EINVAL;
return -1;
}
n++;
if (b == PAD) {
term++;
continue;
}
u |= (unsigned) b;
if (--len == 0)
break;
if (!*s)
break;
}
if (n == 4) {
if (decode(&dest, buf, buflen, u, n-term) < 0)
return -1;
n = 0;
}
}
}
if (n) {
if (!alpha->padding)
u <<= 6 * (4 - n);
if (decode(&dest, buf, buflen, u, n-term) < 0)
return -1;
}
return dest - buf;
}
/*-
* Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include "vmod_blob.h"
#define ILL -1
#define PAD -2
static const struct b64_alphabet {
const char b64[64];
const int8_t i64[256];
const int padding;
} b64_alphabet[] = {
[BASE64] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
"ghijklmnopqrstuvwxyz0123456789+/",
{
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, 62, ILL, ILL, ILL, 63, /* +, - */
52, 53, 54, 55, 56, 57, 58, 59, /* 0 - 7 */
60, 61, ILL, ILL, ILL, PAD, ILL, ILL, /* 8, 9, = */
ILL, 0, 1, 2, 3, 4, 5, 6, /* A - G */
7, 8, 9, 10, 11, 12, 13, 14, /* H - O */
15, 16, 17, 18, 19, 20, 21, 22, /* P - W */
23, 24, 25, ILL, ILL, ILL, ILL, ILL, /* X, Y, Z */
ILL, 26, 27, 28, 29, 30, 31, 32, /* a - g */
33, 34, 35, 36, 37, 38, 39, 40, /* h - o */
41, 42, 43, 44, 45, 46, 47, 48, /* p - w */
49, 50, 51, ILL, ILL, ILL, ILL, ILL, /* x, y, z */
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
},
'='
},
[BASE64URL] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
"ghijklmnopqrstuvwxyz0123456789-_",
{
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, 62, ILL, ILL, /* - */
52, 53, 54, 55, 56, 57, 58, 59, /* 0 - 7 */
60, 61, ILL, ILL, ILL, PAD, ILL, ILL, /* 8, 9, = */
ILL, 0, 1, 2, 3, 4, 5, 6, /* A - G */
7, 8, 9, 10, 11, 12, 13, 14, /* H - O */
15, 16, 17, 18, 19, 20, 21, 22, /* P - W */
23, 24, 25, ILL, ILL, ILL, ILL, 63, /* X-Z, _ */
ILL, 26, 27, 28, 29, 30, 31, 32, /* a - g */
33, 34, 35, 36, 37, 38, 39, 40, /* h - o */
41, 42, 43, 44, 45, 46, 47, 48, /* p - w */
49, 50, 51, ILL, ILL, ILL, ILL, ILL, /* x, y, z */
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
},
'='
},
[BASE64URLNOPAD] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
"ghijklmnopqrstuvwxyz0123456789-_",
{
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, 62, ILL, ILL, /* - */
52, 53, 54, 55, 56, 57, 58, 59, /* 0 - 7 */
60, 61, ILL, ILL, ILL, ILL, ILL, ILL, /* 8, 9 */
ILL, 0, 1, 2, 3, 4, 5, 6, /* A - G */
7, 8, 9, 10, 11, 12, 13, 14, /* H - O */
15, 16, 17, 18, 19, 20, 21, 22, /* P - W */
23, 24, 25, ILL, ILL, ILL, ILL, 63, /* X-Z, _ */
ILL, 26, 27, 28, 29, 30, 31, 32, /* a - g */
33, 34, 35, 36, 37, 38, 39, 40, /* h - o */
41, 42, 43, 44, 45, 46, 47, 48, /* p - w */
49, 50, 51, ILL, ILL, ILL, ILL, ILL, /* x, y, z */
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
},
0
},
};
/*-
* Copyright 2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include "config.h"
#include <ctype.h>
#include <errno.h>
#include "vmod_blob.h"
#include "hex.h"
#include "vdef.h"
#include "vrt.h"
#include "vas.h"
const char hex_alphabet[][16] = {
"0123456789abcdef",
"0123456789ABCDEF"
};
/*
* Shift the ASCII table over so that it begins at '0', and replace the
* hex digits with their binary values. This fits all of the hex digits
* into 55 bytes (cacheline friendly).
*/
const uint8_t nibble[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, 10, 11, 12,
13, 14, 15, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, 10,
11, 12, 13, 14, 15
};
size_t
hex_encode_l(size_t l)
{
return ((l) << 1) + 1;
}
size_t
hex_decode_l(size_t l)
{
return ((l) + 1) >> 1;
}
static inline char
hex2byte(const unsigned char hi, const unsigned char lo)
{
return (nibble[hi - '0'] << 4) | nibble[lo - '0'];
}
ssize_t
hex_encode(const enum encoding enc, char *restrict const buf,
const size_t buflen, const char *restrict const in,
const size_t inlen)
{
char *p = buf;
const char *alphabet = hex_alphabet[0];
AN(buf);
assert(enc == HEXUC || enc == HEXLC);
if (in == NULL || inlen == 0)
return 0;
if (buflen < hex_encode_l(inlen))
return -1;
if (enc != HEXLC)
alphabet = hex_alphabet[1];
for (int i = 0; i < inlen; i++) {
*p++ = alphabet[(in[i] & 0xf0) >> 4];
*p++ = alphabet[in[i] & 0x0f];
}
return p - buf;
}
ssize_t
hex_decode(const enum encoding dec, char *restrict const buf,
const size_t buflen, ssize_t n,
const char *restrict const p, va_list ap)
{
char *dest = buf;
unsigned char extranib = 0;
ssize_t len = 0;
va_list ap2;
AN(buf);
assert(dec == HEX);
va_copy(ap2, ap);
for (const char *s = p; s != vrt_magic_string_end;
s = va_arg(ap2, const char *)) {
const char *b = s;
if (s != NULL)
while (*s)
if (!isxdigit(*s++)) {
len = -1;
break;
}
if (len == -1)
break;
len += s - b;
}
va_end(ap2);
if (len == 0)
return 0;
if (len == -1) {
errno = EINVAL;
return -1;
}
if (n != -1 && len > n)
len = n;
if ((len+1) >> 1 > buflen) {
errno = ENOMEM;
return -1;
}
if (len & 1) {
extranib = '0';
len++;
}
for (const char *s = p; len > 0 && s != vrt_magic_string_end;
s = va_arg(ap, const char *)) {
if (s == NULL || *s == '\0')
continue;
if (extranib) {
*dest++ = hex2byte(extranib, *s++);
len -= 2;
}
while (len >= 2 && *s && *(s+1)) {
*dest++ = hex2byte(*s, *(s+1));
s += 2;
len -= 2;
}
extranib = *s;
}
assert(dest <= buf + buflen);
return dest - buf;
}
/*-
* Copyright 2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include <stdint.h>
#define ILL (0xff)
/* These are defined in hex.c */
extern const char hex_alphabet[][16];
extern const uint8_t nibble[];
/*-
* Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include "config.h"
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include "vmod_blob.h"
#include "vdef.h"
#include "vrt.h"
#include "vas.h"
size_t
id_encode_l(size_t l)
{
return l + 1;
}
size_t
id_decode_l(size_t l)
{
return l;
}
ssize_t
id_encode(const enum encoding enc, char *restrict const buf,
const size_t buflen, const char *restrict const in,
const size_t inlen)
{
(void) enc;
AN(buf);
if (buflen < inlen + 1)
return -1;
if (in == NULL || inlen == 0)
return 0;
memcpy(buf, in, inlen);
return inlen;
}
ssize_t
id_decode(const enum encoding enc,
char *restrict const buf, const size_t buflen,
ssize_t n, const char *restrict const p, va_list ap)
{
char *dest = buf;
size_t outlen = 0, c = SIZE_MAX;
(void) enc;
AN(buf);
if (n >= 0)
c = n;
for (const char *s = p; c > 0 && s != vrt_magic_string_end;
s = va_arg(ap, const char *)) {
size_t len;
if (s == NULL || *s == '\0')
continue;
len = strlen(s);
if (len > c)
len = c;
c -= len;
if ((outlen += len) > buflen) {
errno = ENOMEM;
return -1;
}
memcpy(dest, s, len);
dest += len;
}
return outlen;
}
/*
* for the time being, this code is auto-generated outside the varnishd source
* tree, see
* https://code.uplex.de/uplex-varnish/libvmod-blobcode/blob/master/src/gen_enum_parse.pl
*
* TODO: integrate in vmodtool.py or replace with something else
* cf. the same TODO for the shard director in libvmod_directors
*/
#include "parse_encoding.h"
#define term(c) ((c) == '\0')
enum encoding
parse_encoding (const char *m) {
int p;
enum encoding r;
switch (m[0]) {
case 'B': goto _0B; // BASE64, BASE64URL, BASE64URLNOPAD
case 'H': goto _0H; // HEX, HEXLC, HEXUC
case 'I': goto _0I; // IDENTITY
case 'U': goto _0U; // URL, URLLC, URLUC
default: goto invalid;
}
_0B:
switch (m[1]) {
case 'A': goto _1BA; // BASE64, BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_1BA:
switch (m[2]) {
case 'S': goto _2BAS; // BASE64, BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_2BAS:
switch (m[3]) {
case 'E': goto _3BASE; // BASE64, BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_3BASE:
switch (m[4]) {
case '6': goto _4BASE6; // BASE64, BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_4BASE6:
switch (m[5]) {
case '4': goto _5BASE64; // BASE64, BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_5BASE64:
//BASE64
if (term(m[6])) {
r = BASE64;
p = 6;
goto ok;
}
switch (m[6]) {
case 'U': goto _6BASE64U; // BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_6BASE64U:
switch (m[7]) {
case 'R': goto _7BASE64UR; // BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_7BASE64UR:
switch (m[8]) {
case 'L': goto _8BASE64URL; // BASE64URL, BASE64URLNOPAD
default: goto invalid;
}
_8BASE64URL:
//BASE64URL
if (term(m[9])) {
r = BASE64URL;
p = 9;
goto ok;
}
switch (m[9]) {
case 'N': goto _9BASE64URLN; // BASE64URLNOPAD
default: goto invalid;
}
_9BASE64URLN:
//BASE64URLNOPAD
if ((m[10] == 'O') && (m[11] == 'P') && (m[12] == 'A') && (m[13] == 'D') && (term(m[14]))) {
r = BASE64URLNOPAD;
p = 14;
goto ok;
}
goto invalid;
_0H:
switch (m[1]) {
case 'E': goto _1HE; // HEX, HEXLC, HEXUC
default: goto invalid;
}
_1HE:
switch (m[2]) {
case 'X': goto _2HEX; // HEX, HEXLC, HEXUC
default: goto invalid;
}
_2HEX:
//HEX
if (term(m[3])) {
r = HEX;
p = 3;
goto ok;
}
switch (m[3]) {
case 'L': goto _3HEXL; // HEXLC
case 'U': goto _3HEXU; // HEXUC
default: goto invalid;
}
_3HEXL:
//HEXLC
if ((m[4] == 'C') && (term(m[5]))) {
r = HEXLC;
p = 5;
goto ok;
}
goto invalid;
_3HEXU:
//HEXUC
if ((m[4] == 'C') && (term(m[5]))) {
r = HEXUC;
p = 5;
goto ok;
}
goto invalid;
_0I:
//IDENTITY
if ((m[1] == 'D') && (m[2] == 'E') && (m[3] == 'N') && (m[4] == 'T') && (m[5] == 'I') && (m[6] == 'T') && (m[7] == 'Y') && (term(m[8]))) {
r = IDENTITY;
p = 8;
goto ok;
}
goto invalid;
_0U:
switch (m[1]) {
case 'R': goto _1UR; // URL, URLLC, URLUC
default: goto invalid;
}
_1UR:
switch (m[2]) {
case 'L': goto _2URL; // URL, URLLC, URLUC
default: goto invalid;
}
_2URL:
//URL
if (term(m[3])) {
r = URL;
p = 3;
goto ok;
}
switch (m[3]) {
case 'L': goto _3URLL; // URLLC
case 'U': goto _3URLU; // URLUC
default: goto invalid;
}
_3URLL:
//URLLC
if ((m[4] == 'C') && (term(m[5]))) {
r = URLLC;
p = 5;
goto ok;
}
goto invalid;
_3URLU:
//URLUC
if ((m[4] == 'C') && (term(m[5]))) {
r = URLUC;
p = 5;
goto ok;
}
goto invalid;
ok:
return r;
invalid:
return _INVALID;
(void)p;
}
/*
* for the time being, this code is auto-generated outside the varnishd source
* tree, see
* https://code.uplex.de/uplex-varnish/libvmod-blobcode/blob/master/src/gen_enum_parse.pl
*
* TODO: integrate in vmodtool.py or replace with something else
* cf. the same TODO for the shard director in libvmod_directors
*/
enum encoding {
_INVALID = 0,
IDENTITY,
BASE64,
BASE64URL,
BASE64URLNOPAD,
HEX,
HEXUC,
HEXLC,
URL,
URLLC,
URLUC,
__MAX_ENCODING
};
enum encoding parse_encoding (const char *);
/*-
* Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include "config.h"
#include <errno.h>
#include "vmod_blob.h"
#include "hex.h"
#include "vdef.h"
#include "vrt.h"
#include "vas.h"
/* Decoder states */
enum state_e {
NORMAL,
PERCENT, /* just read '%' */
FIRSTNIB, /* just read the first nibble after '%' */
};
size_t
url_encode_l(size_t l)
{
return (l * 3) + 1;
}
size_t
url_decode_l(size_t l)
{
return l;
}
/*
* Bitmap of unreserved characters according to RFC 3986 section 2.3
* (locale-independent and cacheline friendly)
*/
static const uint8_t unreserved[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0xff, 0x3,
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x47,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
static inline int
isunreserved(const uint8_t c)
{
return (unreserved[c >> 3] & (1 << (c & 7)));
}
static inline int
isoutofrange(const uint8_t c)
{
return (c < '0' || c > 'f');
}
ssize_t
url_encode(const enum encoding enc, char *restrict const buf,
const size_t buflen, const char *restrict const in,
const size_t inlen)
{
char *p = buf;
const char * const end = buf + buflen;
const char *alphabet = hex_alphabet[0];
AN(buf);
assert(enc == URLUC || enc == URLLC);
if (in == NULL || inlen == 0)
return 0;
if (enc != URLLC)
alphabet = hex_alphabet[1];
for (int i = 0; i < inlen; i++) {
if (isunreserved(in[i])) {
if (p == end)
return -1;
*p++ = in[i];
}
else {
if (p + 3 > end)
return -1;
*p++ = '%';
*p++ = alphabet[(in[i] & 0xf0) >> 4];
*p++ = alphabet[in[i] & 0x0f];
}
}
return p - buf;
}
ssize_t
url_decode(const enum encoding dec, char *restrict const buf,
const size_t buflen, ssize_t n, const char *restrict const p,
va_list ap)
{
char *dest = buf;
const char * const end = buf + buflen;
size_t len = SIZE_MAX;
uint8_t nib = 0;
enum state_e state = NORMAL;
AN(buf);
assert(dec == URL);
if (n >= 0 && n < len)
len = n;
for (const char *s = p; len > 0 && s != vrt_magic_string_end;
s = va_arg(ap, const char *)) {
if (s == NULL || *s == '\0')
continue;
while (*s && len) {
uint8_t nib2;
switch(state) {
case NORMAL:
if (*s == '%')
state = PERCENT;
else {
if (dest == end) {
errno = ENOMEM;
return -1;
}
*dest++ = *s;
}
break;
case PERCENT:
if (isoutofrange(*s)
|| (nib = nibble[*s - '0']) == ILL) {
errno = EINVAL;
return -1;
}
state = FIRSTNIB;
break;
case FIRSTNIB:
if (dest == end) {
errno = ENOMEM;
return -1;
}
if (isoutofrange(*s)
|| (nib2 = nibble[*s - '0']) == ILL) {
errno = EINVAL;
return -1;
}
*dest++ = (nib << 4) | nib2;
nib = 0;
state = NORMAL;
break;
default:
WRONG("illegal URL decode state");
}
s++;
len--;
}
}
if (state != NORMAL) {
errno = EINVAL;
return -1;
}
assert(dest <= end);
return dest - buf;
}
This diff is collapsed.
This diff is collapsed.
/*-
* Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include "parse_encoding.h"
#define AENC(enc) assert((enc) > _INVALID && (enc) < __MAX_ENCODING)
/*
* Length estimate interface
*/
typedef
size_t len_f(size_t);
/*
* General interface for an encoder: encode the data at in of length inlen
* into a null-terminated string at buf, and return the length of the
* encoding.
*
* enc: encoding enum (from parse_encoding.h)
* buf: destination of the encoded string
* buflen: maximum length available at buf
* in: source of data to be encoded
* inlen: length of data to be encoded
*
* The regions pointed to by buf and in MUST NOT overlap (this is the
* contract imposed by restrict).
* An encoder SHALL NOT append the terminating null byte (this must
* be done by the caller).
*
* Returns:
* -1, if there is insufficient space at buf, *including* space for the
* terminating null byte
* 0, if the length of the encoding is 0 -- the caller should return
* the static constant empty string (literal "")
* otherwise, the number of bytes written (note that this does not
* include any terminating null byte)
*/
typedef
ssize_t encode_f(const enum encoding enc, char *restrict const buf,
const size_t buflen, const char *restrict const in,
const size_t inlen);
/*
* General interface for a decoder: decode the concatenation of strings
* in p and ap (obtained from a STRING_LIST) into buf, and return the
* length of decoded data.
*
* dec: decoding enum (from parse_encoding.h)
* buf: destination of the decoded data
* buflen: maximum length available at buf
* inlen: maximum length to read or -1 to read up to \0
* p, ap: strings obtained from a VCL STRING_LIST
*
* The regions pointed to by buf and any of the strings in p or ap MUST
* NOT overlap (per restrict).
* Note that the p,ap list is terminated by vrt_magic_string_end, and
* any member of the list may be NULL or empty.
*
* Returns:
* -1, if there is insufficient space at buf, or if the decoding is
* invalid; errno SHALL be set to ENOMEM or EINVALID, respectively
* 0, if the length of the decoding is 0 -- the caller should return
* a static constant empty BLOB
* otherwise, the number of bytes written
*/
typedef
ssize_t decode_f(const enum encoding dec, char *restrict const buf,
const size_t buflen, const ssize_t inlen,
const char *restrict const p, va_list ap);
/* id.c */
len_f id_encode_l;
len_f id_decode_l;
encode_f id_encode;
decode_f id_decode;
/* base64.c */
len_f base64_decode_l;
len_f base64nopad_encode_l;
len_f base64_encode_l;
encode_f base64_encode;
decode_f base64_decode;
/* hex.c */
len_f hex_encode_l;
len_f hex_decode_l;
encode_f hex_encode;
decode_f hex_decode;
/* url.c */
len_f url_encode_l;
len_f url_decode_l;
encode_f url_encode;
decode_f url_decode;
/*-
* Copyright 2015 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: 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.
*
* write buffer: utility functions to append-write on a varnish workspace
*/
#include <string.h>
#include "wb.h"
char *
wb_create(struct ws *ws, struct wb_s *wb)
{
if (WS_Reserve(ws, 0) == 0) {
wb->w = NULL;
wb->ws = NULL;
return NULL;
}
wb->w = ws->f;
wb->ws = ws;
return wb->w;
}
void
wb_reset(struct wb_s *wb)
{
WS_Release(wb->ws, 0);
memset(wb, 0, sizeof(*wb));
}
/*
* release varnish workspace
*
* return start of buffer
*/
char *
wb_finish(struct wb_s *wb, ssize_t *l)
{
char *r = wb->ws->f;
assert(wb->ws->r - wb->w > 0);
if (l)
*l = wb_len(wb);
*wb->w = '\0';
wb->w++;
/* amount of space used */
WS_ReleaseP(wb->ws, wb->w);
return r;
}
/*-
* Copyright 2015-2016 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.
*
*/
#include "cache/cache.h"
struct wb_s {
struct ws *ws; // varnish workspace
char *w; // current write position
};
/* return one byte less for the final zero byte */
static inline const char*
wb_end(struct wb_s *wb) {
return wb->ws->r - 1;
}
/* return the write position */
static inline char*
wb_buf(struct wb_s *wb) {
return wb->w;
}
/* return one byte less for the final zero byte */
static inline ssize_t
wb_space(struct wb_s *wb) {
ssize_t f = wb->ws->r - wb->w;
assert(f > 0);
return f - 1;
}
static inline ssize_t
wb_len(struct wb_s *wb) {
ssize_t l = wb->w - wb->ws->f;
assert(l >= 0);
return l;
}
static inline void
wb_advance(struct wb_s *wb, ssize_t l) {
wb->w += l; // final byte
assert(wb->w < wb_end(wb));
}
char *wb_create(struct ws *ws, struct wb_s *wb);
void wb_reset(struct wb_s *wb);
char *wb_finish(struct wb_s *wb, ssize_t *l);
......@@ -18,7 +18,8 @@ dist_man_MANS = \
vmod_directors.3 \
vmod_purge.3 \
vmod_std.3 \
vmod_vtc.3
vmod_vtc.3 \
vmod_blob.3
CLEANFILES = $(dist_man_MANS)
......@@ -97,4 +98,7 @@ vmod_std.3: $(top_builddir)/lib/libvmod_std/vmod_std.man.rst
vmod_vtc.3: $(top_builddir)/lib/libvmod_vtc/vmod_vtc.man.rst
${RST2MAN} $(RST2ANY_FLAGS) $? $@
vmod_blob.3: $(top_builddir)/lib/libvmod_blob/vmod_blob.man.rst
${RST2MAN} $(RST2ANY_FLAGS) $? $@
.NOPATH: $(dist_man_MANS)
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