Skip to content

Instantly share code, notes, and snippets.

@simonw
Last active May 13, 2021 18:13
Show Gist options
  • Save simonw/640331 to your computer and use it in GitHub Desktop.
Save simonw/640331 to your computer and use it in GitHub Desktop.
Get Varnish to handle JSON-P requests for you
backend default {
.host = "127.0.0.1";
.port = "8000";
}
# 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 = "8070";
}
# 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, "\?&", "?");
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;
esi;
}
}
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 />" # Blank directive, needed to avoid this error:
# ESI_xmlerror: No ESI processing, first char not '<'
"/**/" # http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/
req.http.X-Callback
"(<esi:include src=%22" req.http.X-ESI-Url "%22 />)";
return(deliver);
}
}
@tansengming
Copy link

Thanks for the VCL. Really helped boost up our hit rates.

Note that this will return Content-Type=application/javascript;charset=UTF-8 in the header, which won't work in IE (Reference). Do remember to set it to Content-Type=application/javascript instead.

@simonw
Copy link
Author

simonw commented May 13, 2021

Just spotted this updated version for Varnish 3: https://gist.github.com/xdamman/7340863

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment