varnishtest "VMOD blob decode() n chars 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=blob.decode(URL, 9, req.http.urlucfoobar));

	    set resp.http.declc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 12, req.http.urllcfoobar));

	    set resp.http.dechobbesuc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 27, req.http.urlhobbesuc));

	    set resp.http.dechobbeslc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 27, req.http.urlhobbeslc));

	    set resp.http.decumlautsuc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 17, req.http.urlucumlauts));

	    set resp.http.decumlautslc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 25, req.http.urllcumlauts));

	    set resp.http.decphkuc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 18, req.http.urlucphk));

	    set resp.http.decphklc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 30, req.http.urllcphk));

	    set resp.http.decutf8uc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 9, req.http.urlucutf8));

	    set resp.http.decutf8lc =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 18, req.http.urllcutf8));

	    set resp.http.decalluc =
	      blob.encode(HEX,
			  blob=blob.decode(URL, 252, req.http.urlalluc));

	    set resp.http.decalllc =
	      blob.encode(HEX, UPPER,
			  blob.decode(URL, 252, req.http.urlalllc));

	    set resp.http.decempty =
	      blob.encode(IDENTITY, blob=blob.decode(URL, 10, ""));

	    set resp.http.decemptybyte =
	      blob.encode(IDENTITY, blob=blob.decode(URL, 3, "%00"));

	    set resp.http.decemptypieces =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 1, req.http.unset + ""
						   + req.http.unset + ""));

	    set req.http.part1 = "foo%";
	    set resp.http.dec2pieces =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 6, req.http.part1 +
						   "20bar%20baz%20quux"));

	    set req.http.part2 = "0quux";
	    set resp.http.dec3param =
	      blob.encode(blob=blob.decode(encoded=req.http.part1 +
			      "20bar%20baz%2" + req.http.part2,
			      decoding=URL, length=12),
			      encoding=IDENTITY);

	    set resp.http.dec3pieces =
	      blob.encode(IDENTITY,
			  blob=blob.decode(URL, 18, req.http.part1
						    + "20bar%20baz%2"
						    + req.http.part2));

	    set resp.http.decmanypieces =
	      blob.encode(IDENTITY,
			      blob=blob.decode(URL, 24, "" + 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(URL, UPPER,
					    blob.decode(URL, 1, "%20"));
		}
		elsif (req.url == "/percent-two") {
			set resp.http.bad = blob.encode(URL, UPPER,
					    blob.decode(URL, 2, "%20"));
		}
		elsif (req.url == "/comma") {
			set resp.http.good = blob.encode(IDENTITY, blob=
					     blob.decode(URL, 3, "%2c%q"));
		}
		elsif (req.url == "/colon") {
			set resp.http.good = blob.encode(IDENTITY, blob=
					     blob.decode(URL, 3, "%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
