Skip to content

Instantly share code, notes, and snippets.

@xdamman

xdamman/varnish-jsonp.vcl

Last active Dec 27, 2015
Embed
What would you like to do?
Make Varnish 3.x handle jsonp requests so that we can cache them (even when jQuery generates random callback function names when using $.getJSON). Inspired by https://gist.github.com/simonw/640331 and adapted for Varnish 3.x.
#<jsonp>
# We go BACK to varnish to get it to generate an ESI template that
# generates a JSON-P response.
backend jsonp_template_backend {
.host = "127.0.0.1";
.port = "80"; # use the port that varnish is listening on
}
# <jsonp>
# How the jsonp_template_backend dispatches to the ESI generating code:
sub vcl_recv {
if (req.url == "/JSONP-ESI-TEMPLATE") {
error 760;
}
}
sub vcl_recv {
# If URL includes callback=, rewrite to an ESI template
if (req.url ~ "callback=") {
set req.http.X-Callback = regsub(
req.url, ".*[\?&]callback=([\.A-Za-z0-9_]+).*", "\1"
);
set req.http.X-ESI-Url = regsub(req.url, "&?callback=[\.A-Za-z0-9_]+", "");
# Remove a trailing ?
set req.http.X-ESI-Url = regsub(req.http.X-ESI-Url, "\?$", "");
# Fix any accidental ?&
set req.http.X-ESI-Url = regsub(req.http.X-ESI-Url, "\?&", "?");
# Remove %22 (")
set req.http.X-ESI-Url = regsub(req.http.X-ESI-Url, "%22", "");
set req.url = "/JSONP-ESI-TEMPLATE";
set req.backend = jsonp_template_backend;
return (pass); # NEVER cache template, since it varies on X-Callback/ESI-Url
}
}
sub vcl_fetch {
# X-ESI: 1 from backend triggers ESI processing
if (beresp.http.X-ESI) {
remove beresp.http.X-ESI;
set beresp.do_esi = true;
}
}
sub vcl_fetch {
# X-JSONP-Server means we need to clean up the response a bit
if (beresp.http.X-JSONP-Server) {
remove beresp.http.X-JSONP-Server;
remove beresp.http.Via; # Gets added again later on, but a bit less messy
remove beresp.http.Retry-After;
set beresp.http.Server = "JSONP-Server";
}
}
# We're using a custom error here because it's the only way I could find to get # varnish to compose a custom response.
sub vcl_error {
if (obj.status == 760) {
set obj.http.Content-Type = "application/javascript; charset=utf8";
set obj.http.X-ESI = "1";
set obj.http.X-JSONP-Server = "1";
set obj.status = 200;
set obj.response = "OK";
synthetic {"<esi:include />"} + req.http.X-Callback + {"(<esi:include src="} + req.http.X-ESI-Url + {" />)"};
return(deliver);
}
}
# </jsonp>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment