Discussion:
VCL: returning early from a custom function
Cosimo Streppone
2018-04-11 13:59:22 UTC
Permalink
Hi again,

two messages in a day after a few years :-)

I have code similar to the following (also here[1]):

sub vcl_recv {
...
call rate_limit;
...
}

# Throttling based on request inspection
sub rate_limit {

if (req.url ~ "pattern1") {
std.log("pattern1 requests must never be throttled");
return; # <---- Need to return early here, but can't do it
}

if (req.url ~ "pattern2") {
if (vsthrottle.is_denied("pattern2" + client.identity, 100, 10s)) {
std.log("pattern2 throttling for ip " + client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}

if (vsthrottle.is_denied("ip:" + client.identity, 500, 10s)) {
std.log("global throttling for ip " + client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}

}

Ideally, I'd like to return early from rate_limit() when I know that I don't need
to enforce any rate limiting for some types of requests, but I understand
that's not implemented.

I found some alternatives, though generally they feel uglier.
Any ideas?
--
Cosimo

[1] https://gist.github.com/cosimo/6d3318bf173357dfb2652b7b2e81e1e0#file-gistfile1-txt-L18
Dridi Boukelmoune
2018-04-11 14:30:11 UTC
Permalink
Post by Cosimo Streppone
I found some alternatives, though generally they feel uglier.
Any ideas?
This has been discussed in the past, including the possibility to
return a value, but as of today you can't break out of a subroutine.

https://github.com/varnishcache/varnish-cache/wiki/VIP2%3A-VCL-typed-functions

With this feature you could break out of a subroutine by turning it
into a function that returns VOID. We are not there yet.

Dridi
Anheyer, Tom
2018-04-11 14:43:11 UTC
Permalink
What about:

sub rate_limit {

if (req.url ~ "pattern1") {
std.log("pattern1 requests must never be throttled");
}
else {
if (req.url ~ "pattern2") {
if (vsthrottle.is_denied("pattern2" + client.identity,
100, 10s)) {
std.log("pattern2 throttling for ip " +
client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}

if (vsthrottle.is_denied("ip:" + client.identity, 500, 10s)) {
std.log("global throttling for ip " + client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}

}

tom
Post by Cosimo Streppone
Hi again,
two messages in a day after a few years :-)
sub vcl_recv {
...
call rate_limit;
...
}
# Throttling based on request inspection
sub rate_limit {
if (req.url ~ "pattern1") {
std.log("pattern1 requests must never be throttled");
return; # <---- Need to return early here, but can't do it
}
if (req.url ~ "pattern2") {
if (vsthrottle.is_denied("pattern2" + client.identity, 100, 10s)) {
std.log("pattern2 throttling for ip " + client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}
if (vsthrottle.is_denied("ip:" + client.identity, 500, 10s)) {
std.log("global throttling for ip " + client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}
Ideally, I'd like to return early from rate_limit() when I know that I don't need
to enforce any rate limiting for some types of requests, but I understand
that's not implemented.
I found some alternatives, though generally they feel uglier.
Any ideas?
Cosimo Streppone
2018-04-12 08:27:34 UTC
Permalink
Post by Cosimo Streppone
sub rate_limit {
if (req.url ~ "pattern1") {
std.log("pattern1 requests must never be throttled");
}
else {
if (req.url ~ "pattern2") {
if (vsthrottle.is_denied("pattern2" + client.identity, 100, 10s)) {
std.log("pattern2 throttling for ip " +
client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}
if (vsthrottle.is_denied("ip:" + client.identity, 500, 10s)) {
std.log("global throttling for ip " + client.identity);
return(synth(429, "ETOOMANYREQUESTS"));
}
}
}
Yes, that's one of the alternatives, though the "whitelisted" patterns
are more than just one.

I ended up doing something like:

set req.http.Rate-Limit = "1";

if (whitelisted-pattern1) { set req.http.Rate-Limit = "0"; }
if (whitelisted-pattern2) { set req.http.Rate-Limit = "0"; }
...

if (req.http.Rate-Limit == "0") {
# no rate limiting
} else {
# yes, do rate limit
}

I intend to look at vmod_var to see if I can make this prettier.
--
Cosimo
Loading...