Last active
May 13, 2021 18:13
-
-
Save simonw/640331 to your computer and use it in GitHub Desktop.
Get Varnish to handle JSON-P requests for you
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 toContent-Type=application/javascript
instead.