public
Last active — forked from simonw/varnish-jsonp.vcl

Get Varnish to handle JSONP requests - working example

  • Download Gist
varnish-jsonp.vcl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
backend jsonp_varnish {
.host = "localhost";
.port = "80";
}
 
#------------- begin jsonp functionality -------------#
# How the jsonp_template_backend dispatches to the ESI generating code:
sub jsonp_throw_error_recv {
if (req.url == "/JSONP-ESI-TEMPLATE") {
error 760;
}
}
 
sub jsonp_prepare_request_recv {
# If URL includes callback=, rewrite to an ESI template
 
if (req.url ~ "callback=\S") {
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";
 
# We go BACK to varnish to get it to generate an ESI template that
# generates a JSON-P response.
set req.backend = jsonp_varnish;
return (pass); # NEVER cache template, since it varies on X-Callback/ESI-Url
}
}
 
sub jsonp_begin_esi_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 jsonp_clean_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";
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 '<'
req.http.X-Callback +
{"(<esi:include src="http://your.domain.com"} + req.http.X-ESI-Url + {"" />);"};
 
return(deliver);
}
}
#------------- end jsonp functionality -------------#
 
sub vcl_recv {
call jsonp_throw_error_recv;
call jsonp_prepare_request_recv;
}
 
sub vcl_fetch {
call jsonp_begin_esi_fetch;
call jsonp_clean_fetch;
 
# Add this if You use gzip compression for Your json assets
if ( beresp.http.content-type ~ "application/javascript" ) {
set beresp.do_gzip = true;
}
}

It was a great help! Thx! :)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.