The synthbackend vmod allows the insertion of synthetic object
at the beginning of the fetch pipeline, allowing you to store and manipulate
them exactly like backend-generated response.
Varnish can produce synthetic responses out-of-the-box, but these objects aren’t inserted into the cache, and they aren’t processed the same way (no ESI, gzip processing for example).
vcl 4.0;
import synthbackend;
backend s1 {
  .host = "1.1.1.1";
}
sub vcl_recv {
  # because varnish will reset the method to "GET", we have to store the
  # POST info in a header
  unset req.http.post-method;
  if (req.method == "POST") {
    set req.http.post-method = "yes";
    return (hash);
  }
}
sub vcl_backend_fetch {
  # if the request was a POST, reestablish the method, and set the
  # "mirror" backend that will send back the request body as response body
  if (bereq.http.post-method == "yes") {
    set bereq.method = "POST";
    set bereq.backend = synthbackend.mirror();
    return (fetch);
  }
}
curl can then be used to push content:
curl 'http://example.com/path/to/file.html' --data-binary @file.html
It’s also possible to tell Varnish to fetch a list of URLs to prime the cache.
In this example, vmod_xbody is used to transform the provided list of URLs:
/path/to/page/1
/path/to/page/2
/path/to/page/3
...
into
{{ > /path/to/page/1 }}
{{ > /path/to/page/2 }}
{{ > /path/to/page/3 }}
...
which is vmod_edgestash syntax to trigger subrequests.
In this example, we push the URL file with the LOAD method:
curl 'http://example.com/' --data-binary @url.list -X LOAD
VCL:
import edgestash;
import synthbackend;
import xbody;
backend s1 {
  .host = "1.1.1.1";
}
sub vcl_recv {
  unset req.http.warm-state;
  # set the warm-state header: "top" for the initial request, "sub" for
  # subrequests to be cached
  if (req_top.method == "LOAD") {
    if (req.esi_level == 0) {
      set req.http.warm-state = "top";
      # we don't want the request cached, only its subrequests
      return(pass);
    } else {
      set req.http.warm-state = "sub";
      # convert the request into a HEAD one to avoid sending
      # the body back
      set req.method = "HEAD";
      return(hash);
    }
  }
}
sub vcl_backend_fetch {
  # only use mirror for the top request
  if (bereq.http.warm-state == "top") {
    set bereq.backend = synthbackend.mirror();
  } else {
    set bereq.backend = s1;
  }
}
sub vcl_backend_response {
  # prepare the list for edgestash processing
  if (bereq.http.warm-state == "top") {
    set bereq.backend = synthbackend.mirror();
    xbody.regsub("(.*)\n?", "{{ > \1 }}");
    edgestash.parse_response();
  }
}
sub vcl_deliver {
  # trigger the edgestash processing
  if (req.http.warm-state == "top") {
    edgestash.execute();
    return (deliver);
  }
}
This example uses vmod_cookieplus to retrieve the user cookie and parse
its value into the string that feeds synthbackend.from_string().
vcl 4.0;
import cookieplus;
import synthbackend;
backend default {
  .host = "1.1.1.1";
}
sub vcl_hash {
  #As the returned object depends on the "user" cookie, add it to the hash key
  hash_data(cookieplus.get("user"));
}
sub vcl_backend_fetch {
  set bereq.backend = synthbackend.from_string("Welcome " + cookieplus.get("user"));
}
BACKEND from_blob(BLOB)
Take a BLOB as argument and return a backend that will respond
200 OK with the argument as body. This function must be called from sub vcl_backend_fetch.*
Arguments: None
Type: Function
Returns: Backend
Restricted to: vcl_backend_fetch
BACKEND from_string(STRING)
Take a STRING as argument and return a backend that will respond
200 OK with the argument as body. This function must be called from sub vcl_backend_fetch.
Arguments: None
Type: Function
Returns: Backend
Restricted to: vcl_backend_fetch
BACKEND mirror()
Reflects the request body as response body. If bereq.http.content-encoding
exists, it’ll be copied to beresp.http.content-encoding.
Arguments: None
Type: Function
Returns: Backend
BACKEND null()
Returns a “null” backend, akin to an empty director or a sick backend.
Arguments: None
Type: Function
Returns: Backend
The synthbackend VMOD is available in Varnish Enterprise version 6.0.1r3 and later.