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 "" # 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 "()"; return(deliver); } }