Skip to content

Instantly share code, notes, and snippets.

@saranrapjs
Last active February 15, 2018 19:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save saranrapjs/9c634ad4389ea45eb0aad9738f653bc2 to your computer and use it in GitHub Desktop.
Save saranrapjs/9c634ad4389ea45eb0aad9738f653bc2 to your computer and use it in GitHub Desktop.
Varnish + JSONP example

This is a sample Varnish 4.1-style VCL for using Varnish to cache JSONP requests, where the approach is drawn wholesale from the approach outlined by this great Fastly post.

I've made a few changes from Fastly's example:

  • the VCL functions and syntax have been updated to reflect Varnish 4.1 syntax
  • this also sanitizes the "_" parameter, which jQuery will sometimes also add when you use the $.ajax convenience method
  • some regexes have been modified based on testing

It doesn't do anything to specifically make a given request cache-able (e.g. you'd need to add any logic to sanitize cookies, or modify cache TTL's, etc.)

vcl 4.0;
backend default {
.host = "127.0.0.1";
.port = "80";
}
sub vcl_recv {
unset req.http.callback;
# for JSONP requests, we need to sanitize the "callback" and "_" querystring parameters
if (req.url ~ "[\?&]callback=") {
set req.http.callback = regsub(req.url,
"^.*[\?&]callback=([a-zA-Z]+[^&]+).*$",
"\1");
# sub in "/esi/jsonp-callback" as the callback parameter
set req.url = regsub(req.url,
"([\?&])callback=[a-zA-Z_][^&]+",
"\1callback=%3Cesi%3Ainclude%20src%3D%22%2Fesi%2Fjsonp-callback%22%2F%3E");
# strip the jQuery underscore cache-buster parameter
set req.url = regsub(req.url,
"([\?&])_=((?!&)[0-9]+)",
"\1");
return (hash);
}
if (req.url == "/esi/jsonp-callback") {
# pull the callback parameter from the topmost ESI parent
set req.http.callback = req_top.http.callback;
return (synth(900,"JSONP ESI"));
}
}
sub vcl_backend_response {
# parse ESI's with callback-y URL's always?
if (bereq.url ~ "[\?&]callback=") {
set beresp.ttl = 300s;
set beresp.do_esi = true;
}
}
sub vcl_synth {
if (resp.status == 900) {
set resp.status = 200;
set resp.http.response = "OK";
# We add an empty comment at the start in order to
# protect against content sniffing attacks.
# See https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/
synthetic("/**/ " + req.http.callback);
return (deliver);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment