-
Notifications
You must be signed in to change notification settings - Fork 380
VIP4: Restrict VMOD function call sites
Teach the VCC to conditionally refuse $Function
or $Method
calls.
See also VIP9B $Scope
It started with the fact that VRT functions sometimes expect to be called under certain conditions but nothing really documents or enforces such conditions. These functions could at least assert that their requirements are met if that is not already the case, but this is outside of this VIP's scope.
VMOD functions defined by the ad-hoc VCC can however express this kind of requirements when that makes sense. Besides VMOD constructs like the $Event
function that are not visible in VCL or $Object
constructors that can only be used in vcl_init
all VMOD functions can be called from anywhere.
If a VMOD function calls a VRT function that has a special requirement, the VMOD author could document it, and the VCC could enforce it.
A new $Restrict
token followed by a list of blank-separated restrictions. There's already such a mechanism in generate.py
and general consensus leans towards reusing the same parameters:
-
client
(all client subroutines) -
backend
(all backend subroutines) -
<subroutine>
(a specific subroutine)
Example:
$Function VOID needs_a_bereq(...)
$Restrict backend pipe
Another example:
$Module mtstatus 3 Mean time status for Varnish Cache
$Event event_function
# Both functions use VRT_synth_page
$Function VOID mtstatus(REAL delta)
$Restrict synth
# This function gets the HTML contents from a file, it might be worth caching
$Function VOID html(STRING file = "/usr/share/vmod-mtstatus/page.html")
$Restrict synth backend_error
Some VCL symbols have a scope restriction and the compiler performs those checks when those symbols are passed to a VMOD:
# $Module debug
# $Function VOID sethdr(HEADER, STRING)
sub vcl_deliver {
# the direct symbol case
debug.sethdr(resp.http.foo, "bar");
}
Such checks are typically inapplicable when values come from VMODs:
# $Module strawman
# $Function HEADER get_incompatible_header()
sub vcl_deliver {
# the indirect vmod case
debug.sethdr(strawman.get_incompatible_header(), "this will panic: VRT_selecthttp 'where' invalid");
}
One notable exception to the rule above is the SUB
type. When a subroutine is currently passed as VMOD function or object method argument, the compiler does not verify that the scope is compatible to enable dynamic calls.
We could enforce compiler checks in both cases by creating a VCC signature to disable those checks:
$Module dispatcher
$Function register(STRING hostname, &SUB subroutine)
$Module looper
$Function foreach(SUB subroutine)
A scope type would gain a compiler check enforcement even in the indirect VMOD case, and a VMOD would have to explicitly signal with the &
symbol that the argument may be used from a different call site.
In other words, asking for a scoped TYPE
means that the VMOD expects the argument to be safe at the call site, which means that it has to come from a literal symbol since an expression would otherwise lose that information. On the other hand asking for a scoped &TYPE
implies that the VMOD is responsible for runtime checks, since compiler checks will not happen.