HiI would like to understand how to import libraries into custom VCL files in Fastly?
It does not work using import or include. For example if I want to add std. I tried import std or include std or import "std" in a custom VCL file, but it did not work. How do I do this?
The only ways to create encapsulated features in VCL that I know of are to use inline C, and to import vmods. These features are both unavailable to customers on the Fastly platform because if we let you write or import arbitrary C code it would create a way to escape the memory workspace allocated to your request, and also might unpredictably change the compute and memory requirements of your application. Our VCL services are tuned to operate at incredibly high throughput and do depend on well defined constraints that we can rely on.
For all you can do in VCL, there are things you can not do.Look an IP number up in a database file for instance.VCL provides for inline C code, and there you can do everything,but it is not a convenient or even readable way to solve suchproblems.
As a rule of thumb you, if the VMOD uses more than the VRT (VarnishRunTime), in which case it needs to be built for the exact Varnishversion, use strict. If it complies to the VRT and only needsto be rebuilt when breaking changes are introduced to the VRT API,use vrt.
The $Function lines define three functions in the VMOD, alongwith the types of the arguments, and that is probably where thehardest bit of writing a VMOD is to be found, so we will talk aboutthat at length in a moment.
Object instances are represented as pointers to vmod-implemented Cstructs. Varnish only provides space to store the address of objectinstances and ensures that the right object address gets passed to Cfunctions implementing methods.
The destructor is named by the suffix __fini, always isof VOID return type and has a single argument, thepointer-pointer to the address of the object. The destructoris expected clear the address of the object stored in thatpointer-pointer.
As varnish is in no way involved in managing object instances otherthan passing their addresses, vmods need to implement all aspects ofmanaging instances, in particular their memory management. As thelifetime of object instances is the vcl, they will usually beallocated from the heap.
The $Restrict stanza offers a way to limit the scope of the preceding vmod functionor method, so that they can only be called from restricted vcl call sites.It must only appear after a $Method or $Function and has the following syntax:
Notice that most of the non-native (C pointer) types are const,which, if returned by a vmod function/method, are assumed to beimmutable. In other words, a vmod must not modify any data which waspreviously returned.
When returning non-native values, the producing function isresponsible for arranging memory management. Either by freeing thestructure later by whatever means available or by using storageallocated from the client or backend workspaces.
These are VCL compiler generated constants referencing aparticular header in a particular HTTP entity, for instancereq.http.cookie or beresp.http.last-modified. By passinga reference to the header, the VMOD code can both read and writethe header in question.
This is an opaque type for regular expressions with a VCL scope.The REGEX type is only meant for regular expression literalsmanaged by the VCL compiler. For dynamic regular expressions orcomplex usage see the API from the include/vre.h file.
References to subroutines can be passed into VMODs asarguments and called later through VRT_call(). The scopestrictly is the VCL: vmods must ensure that VCL_SUBreferences never be called from a different VCL.
For more than one invocation of VRT_call(), VMODs mustcheck if VRT_handled() returns non-zero inbetween calls:The called SUB may have returned with an action (anyreturn(x) other than plain return) or may have failedthe VCL, and in both cases the calling VMOD must returnalso, possibly after having conducted some cleanup. Note thatundoing the handling through VRT_handling() is a bug.
The generic malloc(3) / free(3) approach documented above works forall private pointers. It is the simplest and less error prone (as longas allocated memory is properly freed though the fini callback), butcomes at the cost of calling into the heap memory allocator.
PRIV_TASK and PRIV_TOP arguments to methods are not per objectinstance, but per vmod as for ordinary vmod functions. Thus, vmodsrequiring per-task / per top-request state for object instances needto implement other means to associate storage with object instances.
If the VMOD has private global state, which includes any sockets or filesopened, any memory allocated to global or private variables in the C-code etc,it is the VMODs own responsibility to track how many VCLs were loaded ordiscarded and free this global state when the count reaches zero.
VMOD writers are strongly encouraged to release all per-VCL resources for agiven VCL when it emits a VCL_EVENT_COLD event. You will get a chance toreacquire the resources before the VCL becomes active again and be notifiedfirst with a VCL_EVENT_WARM event. Unless a user decides that a given VCLshould always be warm, an inactive VMOD will eventually become cold and shouldmanage resources accordingly.
An event function must return zero upon success. It is only possible to failan initialization with the VCL_EVENT_LOAD or VCL_EVENT_WARM events.Should such a failure happen, a VCL_EVENT_DISCARD or VCL_EVENT_COLDevent will be sent to the VMODs that succeeded to put them back in a coldstate. The VMOD that failed will not receive this event, and therefore mustnot be left half-initialized should a failure occur.
If your VMOD is running an asynchronous background job you can hold a referenceto the VCL to prevent it from going cold too soon and get the same guaranteesas backends with ongoing requests for instance. For that, you must acquire thereference by calling VRT_VCL_Prevent_Discard when you receive a VCL_EVENT_WARM andlater calling VRT_VCL_Allow_Discard once the background job is over. Receiving aVCL_EVENT_COLD is your cue to terminate any background job bound to a VCL.
In this simplified version, you can see that you need at least a VCL-bound datastructure like a PRIV_VCL or a VMOD object to keep track of the referenceand later release it. You also have to provide a description, it will be printedto the user if they try to warm up a cooling VCL:
When a VCL is loaded or unloaded, the event and priv->free arerun sequentially all in a single thread, and there is guaranteedto be no other activity related to this particular VCL, nor arethere init/fini activity in any other VCL or VMOD at this time.
This directory is intended (though not limited) to provide a place forVMODs to create temporary files using mkstemp() and related libcfunctions. VMODs are responsible for cleaning up files which are nolonger required, and they will ultimately be removed when thevarnishd worker process restarts. There is no isolation betweenVMODs (as is the case anyway).
If I were to ask you what is so great about Varnish, you'd probably answer: "the VCL, duh!". And you would be right, but maybe not for the same reason I'm loving it: the Varnish Configuration Language shifts the traditional declarative mindset of configuration to an imperative state.
It gives you great control, allowing you to actually write your policies, but beyond this, it means that plugins (or VMODs) are super easy to write. Because the VCL is imperative, plugins don't have to register themselves, care about hooks, or worry about execution order, making them a library that you can write in a matter of minutes.
Let's try to make this VMOD interesting by having a real purpose. The vmod-example is nice and all, but it's not something you're ever going to use (reminder, it prepends "Hello, " to a string), so we're going to choose something similar but that is actually useful!
Our VMOD is going to be named "vmod-str" and will deal with a few simple string operations that are technically possible with pure VCL, but that can be cumbersome. Here's the list of functions our VMOD is going to implement:
The first line is really the prototype of the function and tells us that it takes one STRING as argument, and will output an INT. STING and INT are part of the simple VMOD-type system, mapping to C types. INT is simply an int, and STRING is a const char * (meaning VMODs can't modify the strings they are given). You can get more info about that mapping here.
But what about the second line? Surely that's useless to the build system! Indeed it is, but not to the user. You see, the vcc file will be used to generate some boilerplate code (yay for automation), but it will also produce the man page for your module. We can check that directly by compiling and looking at the generated man page:
See that vmod_count declaration? It has been created for us, based on the vcc file, and its prototype is pretty close to what we have declared. The only "weird" element is this VRT_CTX, it's a point about the current VCL context, and we'll gladly ignore it for now.
Of course not! We have to test it, and make sure we didn't make some stupid mistake. Our borrowed build system has support for vtc testing, just like in Varnish, so we'll use this and rewrite src/tests/test01.vtc:
Note: we import the module using a macro to grab the .so file in .libs/. In a regular VCL that line just becomes "import str;". Also, count() is not called directly, but via the str namespace: str.count().
There are two little gotchas here. The BOOL type in VMODs is actually just an unsigned int, 0 is false, and anything else is true. This seems pretty natural, especially if you're accustomed to C, but that's really more of a hack than anything else.
Second, you have to run "./configure" for test02.vtc to be taken into account by automake. The build system will pick up any file named following the src/tests/*.vtc pattern, but it will only do so during the configure stage.
3a8082e126