Advertisement
Guest User

nzpost example default.vcl

a guest
May 15th, 2013
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.86 KB | None | 0 0
  1. import std; # needed for std.log
  2.  
  3. # Include the file with the host definitions in it (we'll call nzpost_extract_sitevars from it soon)
  4. include "nzpost_local.vcl";
  5.  
  6. # Separate backends to allow for ratelimiting if required in future. Nginx still decides how to route the request.
  7. backend default {
  8. .host = "127.0.0.1";
  9. .port = "81";
  10. .connect_timeout = 1s;
  11. .first_byte_timeout = 32s;
  12. .between_bytes_timeout = 2s;
  13. }
  14. backend lightweight {
  15. .host = "127.0.0.1";
  16. .port = "81";
  17. .connect_timeout = 1s;
  18. .first_byte_timeout = 32s;
  19. .between_bytes_timeout = 2s;
  20. }
  21.  
  22. # Handles new requests arriving from a client. At this point we haven't checked the cache.
  23. # Here we:
  24. # 1) Standardise the set of incoming headers to increase the chances of a cache hit
  25. # 2) Detect specific circumstances that should bypass the cache
  26. # 3) Extract cookies etc into X-Varnish-Client-[x] headers that can be "varied" on by the server to create different versions of the cache
  27. sub vcl_recv {
  28. # The "js" makes all paths starting with "js/" lightweight. We attach these to the alternative lightweight backend.
  29. if (req.url ~ "^/js/") {
  30. set req.backend = lightweight;
  31. }
  32.  
  33. # Retrieve session ID and roles information (writes ANON into these if they're not available)
  34. # This is where most X-Varnish-Client-[x] headers come from.
  35. call nzpost_extract_sitevars;
  36.  
  37. # If the current request is for a site we don't recognise, pipe it immediately
  38. if (!req.http.X-MATCHED-SITE) {
  39. return (pipe);
  40. }
  41.  
  42. # Load balancer check file should just pipe to avoid any cache interference
  43. if (req.url ~ "lb_check") {
  44. return (pipe);
  45. }
  46.  
  47. # We only deal with GET, HEAD and POST requests. The rest pipe.
  48. if (req.request != "GET" && req.request != "HEAD" && req.request != "POST") {
  49. return (pipe);
  50. }
  51.  
  52. # Allow a grace period for offering "stale" cache data while we're fetching a new copy from the backend
  53. set req.grace = 5m;
  54.  
  55. # Remove HTTP auth header, if present (web server level only)
  56. if (req.http.Authorization) {
  57. unset req.http.Authorization;
  58. }
  59.  
  60. # If there's ETag (If-None-Match) and If-Modified-Since, just use ETag. Varnish isn't very good at 304ing If-Modified-Since.
  61. # Disabled by Neil until ESI ETags can be taken into consideration
  62. #if (req.http.If-Modified-Since && req.http.If-None-Match) {
  63. # unset req.http.If-Modified-Since;
  64. #}
  65.  
  66. # Normalise Accept-Encoding header (we only care about gzip)
  67. if (req.http.Accept-Encoding) {
  68. if (req.http.Accept-Encoding ~ "gzip" && req.http.user-agent !~ "MSIE 6") {
  69. set req.http.Accept-Encoding = "gzip";
  70. } else {
  71. # don't care - remove
  72. unset req.http.Accept-Encoding;
  73. }
  74. }
  75.  
  76. # Force a cache miss if the request is a force-refresh request from the client
  77. # When an "admin" user does this, it causes a purge of alternative variants as well. See vcl_miss.
  78. # We only allow this in dev or if an "nzpost_allow_purge" cookie exists, otherwise bots and malicious users
  79. # use this against us.
  80. if (req.http.Cache-Control ~ "no-cache" && (req.http.Cookie ~ "secret_cookie=1" || req.http.host ~ "dev")) {
  81. # Use this special flag to denote an explicit force refresh. When an admin does this, it
  82. # clears the cache for everyone (all variants). See vcl_hit/vcl_miss.
  83. set req.http.X-Force-Refresh = 1;
  84. set req.http.X-Force-Miss-Reason = "force-refresh";
  85. set req.hash_always_miss = true;
  86. # don't set X-Varnish-Force-Pass, this prevents the replacement page from entering the cache
  87. }
  88.  
  89. # nzpost_cache adds a suffix of "ADMIN" to the roles hash if the user is a special Admin user, who should
  90. # never hit cache. These users may also perform a purge by sending a force refresh.
  91. if (req.http.X-Varnish-Client-Roles ~ "ADMIN$") {
  92. set req.http.X-Varnish-Client-IsAdmin = 1;
  93. set req.http.X-Force-Miss-Reason = "admin";
  94. set req.http.X-Varnish-Force-Pass = 1;
  95. }
  96.  
  97. # If the user has a persistent_login cookie but not a session, we need to drop them into Drupal
  98. # to get their session back. This case will be included in the hash to allow other users to still hit in parallel.
  99. if (req.esi_level == 0 && req.http.X-Varnish-Client-PersistentLogin && req.http.X-Varnish-Client-SID == "ANON") {
  100. set req.http.X-Varnish-Force-Pass = 1;
  101. set req.http.X-Force-Miss-Reason = "persistent-login-needs-validate";
  102. }
  103.  
  104. # If the user has a CAS cookie but not a session, we need to drop them into Drupal
  105. # to get their session back. This case will be included in the hash to allow other users to still hit in parallel.
  106. if (req.esi_level == 0 && req.http.X-Varnish-Client-CASLogin && (req.http.X-Varnish-Client-SID == "ANON" || req.http.X-Varnish-Client-Roles == "ANON")) {
  107. set req.http.X-Varnish-Force-Pass = 1;
  108. set req.http.X-Force-Miss-Reason = "CAS-login-needs-validate";
  109. }
  110.  
  111. # HTTP POST requests should not be cached, but they still pass through the normal mechanism
  112. # so ESI can happen on the response (eg. form errors).
  113. if (req.request == "POST") {
  114. set req.http.X-Varnish-Force-Pass = 1;
  115. set req.http.X-Force-Miss-Reason = "http-post";
  116. }
  117.  
  118. # If the user has cookies, we will look for some flags of interest in them
  119. if (req.http.Cookie) {
  120. # Static files don't need cookies
  121. if (req.url ~ "^/sites/default/files") {
  122. unset req.http.cookie;
  123. }
  124.  
  125. # Respect the NO_CACHE header set by cookie_cache_bypass. This is included in the hash by vcl_hash.
  126. if (req.http.Cookie ~ "NO_CACHE" && req.esi_level == 0) {
  127. set req.http.X-Varnish-Force-Pass = 1;
  128. set req.http.X-Force-Miss-Reason = "cookie-cache-bypass";
  129. }
  130.  
  131. # Scan for and extract any A/B cookies found (for now we just put these in one big cookie. Later we might separate them.)
  132. if (req.http.Cookie ~ "NZPOST_DEFAULT_") {
  133. set req.http.X-Varnish-Client-ToolPrefs = regsuball(req.http.Cookie, "(NZPOST_DEFAULT_.*?=[^;]+)", "\1");
  134. }
  135.  
  136. # Allow varying on Javascript support
  137. if (req.http.Cookie ~ "has_js=1") {
  138. set req.http.X-Varnish-Client-HasJS = 1;
  139. }
  140. }
  141.  
  142. # If this request has restarted, inform the server in case it cares
  143. if (req.restarts > 0) {
  144. set req.http.X-Varnish-Restarts = req.restarts;
  145. }
  146.  
  147. # Unless X-Varnish-Force-Pass has been set, we just perform a standard cache lookup. A pass can never hit.
  148. if (req.http.X-Varnish-Force-Pass) {
  149. set req.hash_always_miss = true;
  150. return (pass);
  151. }
  152. else {
  153. return (lookup);
  154. }
  155. }
  156.  
  157. # Our hash is kept simple - just the host, port and path, plus the miss reason if we're sure we don't
  158. # want the current request to meddle with the already cached version.
  159. # We use server-provided Vary headers combined with X-Varnish-Client-* headers for cache variations rather than hashes.
  160. sub vcl_hash {
  161. # Default URL and host hash
  162. hash_data(req.url);
  163. if (req.http.host) {
  164. hash_data(req.http.host);
  165. } else {
  166. hash_data(server.ip);
  167. }
  168.  
  169. # Include whether the request is HTTP or HTTPS
  170. if (req.http.X-Forwarded-Proto) {
  171. hash_data(":" + req.http.X-Forwarded-Proto);
  172. }
  173. else if (req.http.X-Port) {
  174. hash_data(":" + req.http.X-Port);
  175. }
  176.  
  177. # If there is a reason why this request will never be cacheable, stop it from affecting already cached pages
  178. # Note "admin" is excluded because there's already a Vary header for that.
  179. if (req.http.X-Force-Miss-Reason && req.http.X-Force-Miss-Reason ~ "cookie-cache-bypass|persistent-login-needs-validate|wrapper-page") {
  180. hash_data(req.http.X-Force-Miss-Reason);
  181. }
  182.  
  183. return (hash);
  184. }
  185.  
  186. # Called after the backend request has arrived, here we override TTLs, detect ESIs, and add some headers for later.
  187. sub vcl_fetch {
  188. # Read the X-VARNISH-TTL header from the backend (if present) and use it to set the Varnish TTL only
  189. # See http://open.blogs.nytimes.com/tag/varnish/
  190. if (beresp.http.X-VARNISH-TTL) {
  191. C{
  192. char *ttl;
  193. /* first char in third param is length of header plus colon in octal */
  194. ttl = VRT_GetHdr(sp, HDR_BERESP, "\016X-VARNISH-TTL:");
  195. VRT_l_beresp_ttl(sp, atoi(ttl));
  196. }C
  197. remove beresp.http.X-VARNISH-TTL;
  198. }
  199.  
  200. # Check for errors we'd like to catch locally (you may want to disable this on dev)
  201. if (beresp.status == 500 || beresp.status == 501 || beresp.status == 502 || beresp.status == 504 || beresp.status == 400) {
  202. return (error);
  203. }
  204.  
  205. # Enable ESI parsing only if the server specifies it
  206. if (beresp.http.X-Varnish-ESI == "on") {
  207. set beresp.do_esi = true;
  208. }
  209. else {
  210. set beresp.do_esi = false;
  211. }
  212.  
  213. if (req.esi_level > 0) {
  214. if (beresp.http.set-cookie) {
  215. # ESI responses can't set cookies
  216. unset beresp.http.set-cookie;
  217. }
  218. if (beresp.status != 200) {
  219. return (error);
  220. }
  221. }
  222.  
  223. # Leave the Vary header as it is for now, but store what should be sent to the client and debug headers here
  224. if (beresp.http.Vary) {
  225. # This is based on the cookie strip example on https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
  226. # It works by putting a space in front of entries we want to keep, then purging any that don't start with a space
  227. set beresp.http.X-Varnish-Debug-CustomVary = "," + beresp.http.Vary;
  228. set beresp.http.X-Varnish-Debug-CustomVary = regsuball(beresp.http.X-Varnish-Debug-CustomVary, ", +", ",");
  229. set beresp.http.X-Varnish-Debug-CustomVary = regsuball(beresp.http.X-Varnish-Debug-CustomVary, ",(X-Varnish-Client-[^,]+)", ", \1");
  230. set beresp.http.X-Varnish-Debug-CustomVary = regsuball(beresp.http.X-Varnish-Debug-CustomVary, ",[^ ][^,]*", "");
  231. set beresp.http.X-Varnish-Debug-CustomVary = regsuball(beresp.http.X-Varnish-Debug-CustomVary, "^[, ]+|[, ]+$", "");
  232. if (beresp.http.X-Varnish-Debug-CustomVary == "") {
  233. unset beresp.http.X-Varnish-Debug-CustomVary;
  234. }
  235.  
  236. # Now extract all the cookies that aren't X-Varnish-Client-* as the set of Vary headers to send to the client
  237. # This is swapped out in vcl_deliver
  238. set beresp.http.X-Varnish-Client-Vary = regsuball(beresp.http.Vary, "(^|, ?) *X-Varnish-Client-[^,]+,? *", "\1");
  239. if (beresp.http.X-Varnish-Client-Vary == "") {
  240. # Just set a sensible default
  241. set beresp.http.X-Varnish-Client-Vary = "Accept-Encoding";
  242. }
  243. }
  244.  
  245. # Static files have fixed cache lifetimes in Varnish (not too long, don't want to clog ourselves up)
  246. # This is mostly to hold gzip'd css/js in cache to avoid having to zip it multiple times.
  247. if (req.url ~ "\.(jpe?g|gif|png)(\?.*)?$" && req.url !~ "^/system/files/private") {
  248. set beresp.ttl = 60s;
  249. }
  250. else if (req.url ~ "\.(css|js)(\?.*)?$" && req.url !~ "^/system/files/private") {
  251. set beresp.ttl = 1h;
  252. }
  253.  
  254. # 200 requests are cached as per the server's advice
  255. # 301 requests are cached for 10 minutes
  256. # 404 responses are cached for 1 minute
  257. # Any other code is never cached
  258. # Non-200 ESI blocks are never cached
  259. if (beresp.status == 200) {
  260. # Do nothing special
  261. }
  262. else if (beresp.status == 301 && req.esi_level == 0) {
  263. set beresp.ttl = 10m;
  264. }
  265. else if (beresp.status == 404 && req.esi_level == 0) {
  266. set beresp.ttl = 60s;
  267. }
  268. else {
  269. # Don't cache
  270. set beresp.ttl = 0s;
  271. }
  272.  
  273. if (beresp.http.Set-cookie) {
  274. if (beresp.http.Set-cookie == "") {
  275. unset beresp.http.Set-cookie;
  276. }
  277. else {
  278. # If the request sets a cookie, caching this is a very bad idea.
  279. set beresp.ttl = 0s;
  280. set beresp.http.X-Varnish-Refuse-Cache = "set-cookie";
  281. }
  282. }
  283.  
  284. set beresp.http.X-Varnish-Debug-TTL = beresp.ttl;
  285.  
  286. # For ban lurker-friendly cache entries (for the Varnish module)
  287. # The x-sid variable is just for us, to purge per-user ESIs easier.
  288. set beresp.http.x-url = req.url;
  289. set beresp.http.x-host = req.http.host;
  290. if (req.http.X-Varnish-Client-SID && beresp.http.vary ~ "X-Varnish-Client-SID") {
  291. set beresp.http.x-sid = req.http.X-Varnish-Client-SID;
  292. }
  293.  
  294. # Force the gzipping of responses that could benefit that nginx has neglected to gzip for some reason.
  295. # This is quite important, due to https://www.varnish-cache.org/trac/ticket/1029 as otherwise Varnish
  296. # will cache an uncached version of the page against the Accept-encoding: gzip header, so any request for
  297. # the resources gzipped will be ungzipped. When combined with ESIs, this can mean a non-gzipped page with gzipped
  298. # ESIs is rendered, which is really ugly. See Fog#4054.
  299. # It's now important in vcl_recv to discover cases where clients shouldn't get gzip and remove accept-encoding.
  300. if (beresp.http.content-type ~ "^text/.+") {
  301. set beresp.do_gzip = true;
  302. }
  303.  
  304. # To finish up, we need to carefully determine whether to use hit_for_pass to allow
  305. # concurrent requests for the same URL to stack up waiting for this one to finish, or
  306. # to simply go in paralell with us. It doesn't make sense for client requests to a page
  307. # that is never cacheable to have to go serially all the time, so a hit_for_pass is required
  308. # in this case.
  309. if (beresp.ttl <= 0s && req.http.X-Varnish-Force-Pass) {
  310. # Force-refresh or other force-fallthrough shouldn't set hit_for_pass as the 0 TTL may be only for this request.
  311. std.log("Force-pass -> deliver");
  312. std.log(req.http.X-Varnish-Force-Pass);
  313. return (deliver);
  314. }
  315. else if (beresp.ttl <= 0s) {
  316. # Normal uncacheable page - cache that it's uncacheable to allow parallel requests for the next 2 minutes
  317. std.log("Normal uncacheable -> hit_for_pass");
  318. set beresp.ttl = 120s;
  319. return (hit_for_pass);
  320. }
  321. else {
  322. # Normal cacheable page, stack requests up to avoid cache slam.
  323. std.log("Normal cacheable -> deliver");
  324. return (deliver);
  325. }
  326. }
  327.  
  328. # This is called on both cache hit and miss to do any final preparations to the reponse before blatting it
  329. # to the client. Here we swap some headers around and write some debugging information about the request.
  330. sub vcl_deliver {
  331. if (obj.hits > 0) {
  332. set resp.http.X-Varnish = "HIT";
  333. }
  334. else {
  335. set resp.http.X-Varnish = "MISS";
  336. }
  337.  
  338. if (resp.http.X-Varnish-Client-Vary) {
  339. # Swap back the Vary header that we want the client to see, clearing the internal-only Vary headers
  340. # This was initially set back in vcl_fetch. The internal-only Vary headers are copied to X-Varnish-Debug-CustomVary
  341. set resp.http.Vary = resp.http.X-Varnish-Client-Vary;
  342. unset resp.http.X-Varnish-Client-Vary;
  343. }
  344.  
  345. if (req.http.X-Force-Miss-Reason) {
  346. set resp.http.X-Force-Miss-Reason = req.http.X-Force-Miss-Reason;
  347. }
  348.  
  349. # Unset some crufty headers the user doesn't need
  350. unset resp.http.x-url;
  351. unset resp.http.x-host;
  352. unset resp.http.x-sid;
  353. }
  354.  
  355. # If we found a match in the cache, this is called.
  356. sub vcl_hit {
  357. if (req.http.X-Force-Refresh && req.http.X-Varnish-Client-IsAdmin) {
  358. # When an admin user performs a force-refresh, we should purge all variants of the current page for all users.
  359. purge;
  360. }
  361. }
  362.  
  363. # If we didn't find a match in the cache, this is called shortly before fetching from the backend.
  364. sub vcl_miss {
  365. if (req.http.X-Force-Refresh && req.http.X-Varnish-Client-IsAdmin) {
  366. # When an admin user performs a force-refresh, we should purge all variants of the current page for all users.
  367. purge;
  368. }
  369.  
  370. # Force accept-encoding: gzip on all requests, regardless of whether the client can do it.
  371. #set req.http.accept-encoding = "gzip";
  372. }
  373.  
  374. # This is called when we ask for the connection to pipe in vcl_recv. We just make sure it shuts the connection.
  375. sub vcl_pipe {
  376. # If we don't set the Connection: close header, any following
  377. # requests from the client will also be piped through and
  378. # left untouched by varnish. We don't want that.
  379. set req.http.connection = "close";
  380.  
  381. # Note: no "pipe" action here - we'll fall back to the default
  382. # pipe method so that when any changes are made there, we
  383. # still inherit them.
  384. }
  385.  
  386. # Called when an error occurs
  387. sub vcl_error {
  388. if (obj.status == 750) {
  389. # This is a redirect
  390. set obj.http.Location = "http://" + req.http.host + req.http.redirect_to;
  391. set obj.http.X-Redirected-By = "Varnish";
  392. set obj.status = 302;
  393. return (deliver);
  394. }
  395.  
  396. if (req.esi_level > 0) {
  397. # Retry the request once if there's an error before giving up
  398. if (req.restarts < 2) {
  399. set req.grace = 60s;
  400. return (restart);
  401. }
  402. set obj.http.content-type = "text/plain";
  403. synthetic {"<!-- ESI error "} + obj.status + {" -->"};
  404. }
  405. else {
  406. set obj.http.content-type = "text/html";
  407. synthetic {"
  408. <!-- Error from Varnish -->
  409. <!doctype html>
  410. <!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
  411. <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
  412. <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
  413. <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
  414. <!-- Consider adding a manifest.appcache: h5bp.com/d/Offline -->
  415. <!--[if gt IE 8]><!--><html class="no-js" lang="en"><!--<![endif]-->
  416. <head>
  417. <meta charset="utf-8">
  418. <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
  419. <meta name="viewport" content="width=device-width">
  420. <title>Technical difficulties | New Zealand Post</title>
  421. <link type="text/css" rel="stylesheet" href="/error-documents/assets/errorStyles.min.css" media="screen" />
  422. </head>
  423. <body>
  424. <div id="main-wrapper">
  425. <div id="header">
  426. <a id="logo" href="http://www.nzpost.co.nz" title="Home" rel="home">
  427. <span id="nzpost-logo"><img width="207" height="40" src="/error-documents/assets/nzpost.png" alt="New Zealand Post" /></span>
  428. </a>
  429. </div>
  430. <div id="main">
  431. <h2>Our New Zealand Post website is experiencing technical difficulties. We apologise for the inconvenience.
  432. </h2>
  433. <p>Please try your request again later, or if you need assistance you can call us on <strong>0800 782 677</strong>.</p>
  434. <p>Visit our <a href="http://status.nzpost.co.nz/" title="View New Zealand Post Performance and Status page">Performance and Status</a> page to see details on the current status of this website.</p>
  435. </div>
  436. </div>
  437. <!-- Technical difficulties analytics -->
  438. <script type="text/javascript">
  439. <!--//--><![CDATA[//><!--
  440. if (document.location.hostname == 'www.nzpost.co.nz' && !document.location.pathname.match(new RegExp('^/admin'))) {
  441. var _gaq = _gaq || [];_gaq.push(["_setAccount", "UA-3139598-1"]);_gaq.push(["_setDomainName", ".nzpost.co.nz"]);(function() {var ga = document.createElement("script");ga.type = "text/javascript";ga.async = true;ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";var s = document.getElementsByTagName("script")[0];s.parentNode.insertBefore(ga, s);})();
  442. window._gaq.push(['_trackEvent', 'Technical difficulties', 'Varnish', document.location.pathname.replace(new RegExp('^/user/\\d+'), '/user/me')]);
  443. }
  444. //--><!]]>
  445. </script>
  446. </body>
  447. </html>
  448. "};
  449. }
  450. return (deliver);
  451. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement