put synth read from disk in it's place

put synth read from disk in it's place

/* Varnish 4 example config for Drupal 7 / Pressflow 6 & 7 */
# Original source: https://github.com/NITEMAN/varnish-bites/varnish4/drupal-base.vcl
# Copyright (c) 2015 Pedro González Serrano and individual contributors.
# MIT License

# Intended to be used both in simple production environments and with
# learning/teaching purposes.
# Some references may not be yet updated to VCL 4.0, we use SeeV3 then.

# WARNING:
# Note that the built-in logic will be appended to our code if no return is performed before.
# Built-in logic is included commented out right after our's for reference purposes in that cases.
# See https://www.varnish-cache.org/trac/wiki/VCLExampleDefault

#######################################################################
# Initialization: Version & imports;

/* Version statement */
# Since Varnish 4.0 it's mandatory to declare VCL version on first line.
vcl 4.0;

/* Module (VMOD) imports */
# Standard module
# See https://www.varnish-cache.org/docs/4.0/reference/vmod_std.generated.html
import std;

# Directors module
# See https://www.varnish-cache.org/docs/4.0/reference/vmod_directors.generated.html
# Unused in simple configs.
#import directors;

#######################################################################
# Probe, backend, ACL and subroutine definitions

/* Backend probes / healthchecks */
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#probes
probe basic {
  /* Only test that backend's IP serves content for '/' */
  # This might be a too heavy probe
  # .url = "/";
  /* Only test that backend's IP has apache working */
  # Nginx would fail this probe with a default config
  .request =
    "OPTIONS * HTTP/1.1"
    "Host: *"
    "Connection: close";
  .interval = 10s;
  .timeout = 2s;
  .window = 8;
  .threshold = 6;
}

/* Backend definitions.*/
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#backend-definition
backend default {
  /* Default backend on the same machine. WARNING: timeouts could be not big enought for certain POST request */
  .host = "127.0.0.1";
  .port = "8008";
  .connect_timeout = 60s;
  .first_byte_timeout = 60s;
  .between_bytes_timeout = 60s;
  .probe = basic;
}

/* Access Control Lists */
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#access-control-list-acl
acl purge_ban {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use '"localhost";' instead
}
acl allowed_monitors {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use'"localhost";' instead
}
#acl own_proxys {
#  "127.0.0.1"/32; // We can use'"localhost";' instead
#}

/* Custom subroutines */
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#subroutines
#TODO# Test in Varnihs 4
# Empty in simple configs.
# We can name subs with no restrictions but as a task can need several chunks of code in diferent states,
# it's a good idea to identify what main sub will call each with a suffix.
# /* Example 301 client redirection removing "www" prefix from request */
# sub perm_redirections_recv {
#   if ( req.http.host ~ "^www.*$" ) {
#     return(synth(751, "http://" + regsub(req.http.host, "^www\.", "") + req.url));
#   }
# }
# sub perm_redirections_synth {
#   if (resp.status == 751) {
#     /* Get new URL from the response */
#     set resp.http.Location = resp.response;
#     /* Set HTTP 301 for permanent redirect */
#     set resp.status = 301;
#     return (deliver);
#   }
# }

#######################################################################
# Client side

# vcl_recv: Called at the beginning of a request, after the complete request has been received and parsed.
# Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-recv
sub vcl_recv {
  /* 0th: general bypass, general return & authorization checks */
  # Empty in simple configs.
  # Useful for debugging we can pipe or pass the request to default backend here to bypass completely Varnish.
  # return (pipe);
  # return (pass);
  # We can also return here a 200 Ok for network performance benchmarking.
  # return(synth(200, "Ok"));
  # Finally we can perform basic HTTP authentification here, by example.
  # SeeV3 http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* 1st: Check for Varnish special requests */
  # Custom response implementation example in order to check that Varnish is working properly.
  # This is usefull for automatic monitoring with monit or when Varnish is behind another proxies like HAProxy.
  if ( ( req.http.host == "monitor.server.health"
      || req.http.host == "health.varnish" )
    && client.ip ~ allowed_monitors
    && ( req.method == "OPTIONS" || req.method == "GET" )
  ) {
    return(synth(200, "Ban added"));
  }
  # Purge logic
  # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#http-purging
  # SeeV3 https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.method == "PURGE") {
    if (!client.ip ~ purge_ban) {
      return(synth(405, "Not allowed."));
    }
    return (purge);
  }
  # Ban logic
  # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#bans
  if (req.method == "BAN") {
    if (!client.ip ~ purge_ban) {
      return(synth(405, "Not allowed."));
    }
    ban("req.http.host == " + req.http.host +
      "&& req.url == " + req.url);
    return(synth(200, "Ban added"));
  }

  /* 2nd: Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_recv;
  # Here we can also enforce SSL when Varnish run behind some SSL termination point.

  /* 3rd: Time for backend choice */
  # Empty in simple configs.

  /* 4th: Prepare headers for the backend */
  # Empty in simple configs.
  # Example remove own_proxys from X-Forwarded-For
  # See https://www.varnish-cache.org/docs/4.0/whats-new/upgrading.html#x-forwarded-for-is-now-set-before-vcl-recv
  # if ( req.restarts == 0
  #   && client.ip ~ own_proxys
  #   && req.http.x-forwarded-for
  # ) {
  #   set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, ",( )?" + client.ip, "");
  # }

  /* 5th: Bypass breakpoint 1 */
  # Useful for debugging we can now pipe or pass the request to backend with headers setted.
  # return (pipe);
  # return (pass);

  /* 6th: Decide if we should deal with a request (mostly copied from built-in logic) */
  if (req.method == "PRI") {
    /* We do not support SPDY or HTTP/2.0 */
    return (synth(405));
  }
  if ( req.method != "GET"
    && req.method != "HEAD"
    && req.method != "PUT"
    && req.method != "POST"
    && req.method != "TRACE"
    && req.method != "OPTIONS"
    && req.method != "DELETE"
  ) {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
  }
  if (req.method != "GET" && req.method != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
  }
  if (req.http.Authorization) {
    /* Not cacheable by default */
    return (pass);
  }

  /* 7th: Access control for some URLs by ACL */
  # Empty in simple configs.
  # By example denial some URLs depending on client-ip, we'll need to define corresponding ACL 'internal'.
  # if ( req.url ~ "^/(cron|install)\.php"
  #   && ! client.ip ~ internal
  # ) {
  #   # Have Varnish throw the error directly.
  #   return(synth(403, "Forbidden."));
  #   # Use a custom error page that you've defined in Drupal at the path "404".
  #   # set req.url = "/403";
  # }

  /* 8th: Custom exceptions */
  # Host exception example:
  # if (req.http.host == "ejemplo.exception.com") {
  #     return (pass);
  # }
  # Drupal exceptions, edit if we want to cache some AJAX/AHAH request.
  # Add here filters for never cache URLs such as Payment Gateway's callbacks
  if (req.url ~ "^/status\.php$" ||
      req.url ~ "^/update\.php$" ||
      req.url ~ "^/ooyala/ping$" ||
      req.url ~ "^/admin/build/features" ||
      req.url ~ "^/info/.*$" ||
      req.url ~ "^/flag/.*$" ||
      req.url ~ "^.*/ajax/.*$" ||
      req.url ~ "^.*/ahah/.*$") {
    /* Do not cache these paths */
    return (pass);
  }
  # Pipe these paths directly to backend for streaming.
  if (req.url ~ "^/admin/content/backup_migrate/export") {
    return (pipe);
  }
  if (req.url ~ "^/system/files") {
    return (pipe);
  }

  /* 9th: Serve from anonymous cahe if all backends are down */
  if (! std.healthy(req.backend_hint) ) {
  #TODO# Consider moving this to vcl_backend_fetch
    unset req.http.Cookie;
    #TODO# Add sick marker
  }

  /* 10th: Deal with compression and the Accept-Encoding header */
  # Althought Varnish 3 handles gziped content itself by default, just to be sure we want to
  # remove Accept-Encoding for some compressed formats.
  # See https://www.varnish-cache.org/docs/4.0/phk/gzip.html#what-does-http-gzip-support-do
  # See https://www.varnish-cache.org/docs/4.0/users-guide/compression.html
  # See https://www.varnish-cache.org/docs/4.0/reference/varnishd.html?highlight=http_gzip_support
  # See (for older configs) https://www.varnish-cache.org/trac/wiki/VCLExampleNormalizeAcceptEncoding
  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|mp4|flv|zip|rar)$") {
      /* Already compressed formats, no sense trying to compress again */
      unset req.http.Accept-Encoding;
    }
  }

  /* 11th: Another header manipulation */
  # Empty in simple configs.
  # We could add here a custom header grouping User-agent families.

  /* 12th: Cookie removal */
  # Always cache the following static file types for all users.
  # Use with care if we control certain downloads depending on cookies.
  # Be carefull also if appending .htm[l] via Drupal's clean URLs.
  if ( req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|woff2|svg|pdf)(\?(itok=)?[a-z0-9_=\.\-]+)?$"
    && req.url !~ "/system/storage/serve"
  ) {
      unset req.http.Cookie;
  }
  # Remove all cookies that backend doesn't need to know about.
  # See https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
  if (req.http.Cookie) {
    /* Warning: Not a pretty solution */
    /* Prefix header containing cookies with ';' */
    set req.http.Cookie = ";" + req.http.Cookie;
    /* Remove any spaces after ';' in header containing cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    /* Prefix cookies we want to preserve with one space */
    /* 'S{1,2}ESS[a-z0-9]+' is the regular expression matching a Drupal session cookie ({1,2} added for HTTPS support) */
    /* 'NO_CACHE' is usually set after a POST request to make sure issuing user see the results of his post */
    /* 'OATMEAL' & 'CHOCOLATECHIP' are special cookies used by Drupal's Bakery module to provide Single Sign On */
    /* Keep in mind we should add here any cookie that should reach the backend such as splahs avoiding cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, ";(S{1,2}ESS[a-z0-9]+|NO_CACHE|OATMEAL|CHOCOLATECHIP)=", "; \1=");
    /* Remove from the header any single Cookie not prefixed with a space until next ';' separator */
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    /* Remove any '; ' at the start or the end of the header */
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      /* If there are no remaining cookies, remove the cookie header. */
      unset req.http.Cookie;
    }
  }

  /* 13th: Session cookie & special cookies bypass caching stage */
  # As we might want to cache some requests, hashed with its cookies,
  # we don't simply pass when some cookies remain present at this point.
  # Instead we look for request that must be passed due to the cookie header.
  if ( req.http.Cookie ~ "SESS"
    || req.http.Cookie ~ "SSESS"
    || req.http.Cookie ~ "NO_CACHE"
    || req.http.Cookie ~ "OATMEAL"
    || req.http.Cookie ~ "CHOCOLATECHIP"
  ) {
    return (pass);
  }

  /* 14th: Bypass breakpoint 2 */
  # Useful for debugging we can now pipe or pass the request to backend to bypass cache.
  # return (pipe);
  # return (pass);

  /* 15th: Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning inconditionally.
  return (hash);
}

# vcl_pipe: Called upon entering pipe mode.
# In this mode, the request is passed on to the backend,
# and any further data from either client or backend is passed on unaltered until either end closes the connection.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-pipe
# sub vcl_pipe {
#     # By default Connection: close is set on all piped requests, to stop
#     # connection reuse from sending future requests directly to the
#     # (potentially) wrong backend. If you do want this to happen, you can undo
#     # it here.
#     # unset bereq.http.connection;
#     return (pipe);
# }

# vcl_pass: Called upon entering pass mode.
# In this mode, the request is passed on to the backend, and the backend's response is passed on to the client,
# but is not entered into the cache.
# Subsequent requests submitted over the same client connection are handled normally.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-pass
# sub vcl_pass {
#     return (fetch);
# }

# vcl_hash: You may call hash_data() on the data you would like to add to the hash.
# Hash is used by Varnish to uniquely identify objects.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-hash
sub vcl_hash {
  /* Hash cookie data */
  # As requests with same URL and host can produce diferent results when issued with different cookies,
  # we need to store items hashed with the associated cookies. Note that cookies are already sanitized when we reach this point.
  if (req.http.Cookie) {
    /* Include cookie in cache hash */
    hash_data(req.http.Cookie);
  }

  /* Custom header hashing */
  # Empty in simple configs.
  # Example for caching differents object versions by device previously detected (when static content could also vary):
  # if (req.http.X-UA-Device) {
  #   hash_data(req.http.X-UA-Device);
  # }
  # Example for caching diferent object versions by X-Forwarded-Proto, trying to be smart about what kind of request
  # could generate diffetent responses.
  if ( req.http.X-Forwarded-Proto
    && req.url !~ "(?i)\.(png|gif|jpeg|jpg|ico|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|woff2|svg|pdf)(\?(itok=)?[a-z0-9_=\.\-]+)?$") {
    hash_data(req.http.X-Forwarded-Proto);
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (lookup);
# }

# vcl_purge: Called after the purge has been executed and all its variants have been evited.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-purge
# sub vcl_purge {
#     return (synth(200, "Purged"));
# }

# vcl_hit: Called after a cache lookup if the requested document was found in the cache.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-hit
sub vcl_hit {
  if (obj.ttl >= 0s) {
    // A pure unadultered hit, deliver it
    return (deliver);
  }
  /* Allow varnish to serve up stale content if it is responding slowly */
  # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
  if (obj.ttl + 60s > 0s) {
    // Object is in grace, deliver it
    // Automatically triggers a background fetch
    return (deliver);
  }
  /* Allow varish to serve up stale content if all backends are down */
  # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
  if ( ! std.healthy(req.backend_hint)
    && obj.ttl + obj.grace > 0s
  ) {
    // Object is in grace, deliver it
    // Automatically triggers a background fetch
    return (deliver);
  }
  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning inconditionally.
  // fetch & deliver once we get the result
  return (fetch);
}

# vcl_miss: Called after a cache lookup if the requested document was not found in the cache.
# Its purpose is to decide whether or not to attempt to retrieve the document from the backend, and which backend to use.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-miss
# sub vcl_miss {
#     return (fetch);
# }

# vcl_deliver: Called before an object is delivered to the client
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-deliver
sub vcl_deliver {
  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # Add whether the object is a cache hit or miss and the number of hits for the object.
  # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
  # In Varnish 4 the obj.hits counter behaviour has changed (see bug 1492), so
  # we use a different method: if X-Varnish contains only 1 id, we have a miss,
  # if it contains more (and therefore a space), we have a hit.
  if (resp.http.x-varnish ~ " ") {
    set resp.http.X-Cache = "HIT";
    # Since in Varnish 4 the behaviour of obj.hits changed, this might not be accurate
    # See https://www.varnish-cache.org/trac/ticket/1492
    set resp.http.X-Cache-Hits = obj.hits;
  } else {
    set resp.http.X-Cache = "MISS";
    /* Show the results of cookie sanitization */
    set resp.http.X-Cookie = req.http.Cookie;
  }

  #TODO# Add sick marker

  # Restart count
  if ( req.restarts > 0) {
    set resp.http.X-Restarts = req.restarts;
  }

  # Add the Varnish server hostname
  set resp.http.X-Varnish-Server = server.hostname;
  # If we have setted a custom header with device family detected we can show it:
  # if (req.http.X-UA-Device) {
  #   set resp.http.X-UA-Device = req.http.X-UA-Device;
  # }
  # If we have recived a custom header with the protocol in the request we can show it:
  # if (req.http.X-Forwarded-Proto) {
  #   set resp.http.X-Forwarded-Proto = req.http.X-Forwarded-Proto;
  # }

  /* Vary header manipulation */
  # Empty in simple configs.
  # By example, if we are storing & serving diferent objects depending on User-Agent header we must set the correct Vary header:
  # if (resp.http.Vary) {
  #   set resp.http.Vary = resp.http.Vary + ",User-Agent";
  # } else {
  #   set resp.http.Vary = "User-Agent";
  # }

  /* Fake headers */
  # Empty in simple configs
  # We can fake server headers here, by example:
  # set resp.http.Server = "Deep thought";
  # set resp.http.X-Powered-By = "BOFH";
  # Or have some fun with headers:
  # See http://www.nextthing.org/archives/2005/08/07/fun-with-http-headers
  # See http://royal.pingdom.com/2012/08/15/fun-and-unusual-http-response-headers/
  # set resp.http.X-Thank-You = "for bothering to look at my HTTP headers";
  # set resp.http.X-Answer = "42";

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_deliver {
#     return (deliver);
# }

# vcl_synth: Called to deliver a synthetic object. A synthetic object is generated in VCL,
# not fetched from the backend. It is typically contructed using the synthetic() function.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-synth
/*
 * We can come here "invisibly" with the following errors: 413, 417 & 503
 */
sub vcl_synth {
  /* Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_synth;

  /* Try to restart request in case of failure */
  # Note that max_restarts defaults to 4
  # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
  if (resp.status == 503 && req.restarts < 4) {
    return(restart);
  }

  /* Set common headers for synthetic responses */
  set resp.http.Content-Type = "text/html; charset=utf-8";

  /* HTTP Authentification client request */
  # Empty in simple configs. SeeV3 http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* Load synthetic responses from disk */
  #TODO# Ensure that this is only done at boot time and we don't hit disk in-flight
  # Example custom 403 error page.
  # if (resp.status == 403) {
  #   synthetic(std.fileread("/403.html"));
  #   return(deliver);
  # }

  /* Error page & refresh / redirections */
  # We have plenty of choices when we have to serve an error to the client,
  # from the default error page to javascript black magic or plain redirections.
  # Adding some external statistic javascript to track failures served to clients is strongly suggested.
  # We can't use external resources on synthetic content, everything must be inlined.
  # If we need to include images we can embed them in base64 encoding.
  # Here is the default error page for Varnish 4 (not so pretty)
  # We're using error 200 for monitoring puposes which should not be retried client side */
  if ( resp.status != 200) {
    set resp.http.Retry-After = "5";
  }

  # Consider add some analytics stuff to trace accesses
  synthetic( {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + resp.status + " " + resp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + resp.status + " " + resp.reason + {"</h1>
    <p>"} + resp.reason + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"} );

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning inconditionally.
  return (deliver);
}

#######################################################################
# Backend Fetch

# vcl_backend_fetch: Called before sending the backend request. In this subroutine you typically alter the request before it gets to the backend.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-backend-fetch
# sub vcl_backend_fetch {
#     return (fetch);
# }

# vcl_backend_response: Called after the response headers has been successfully retrieved from the backend.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-backend-response
sub vcl_backend_response {
  /* Caching exceptions */
  # Varnish will cache objects with response codes: 200, 203, 300, 301, 302, 307, 404 & 410.
  # SeeV3 https://www.varnish-software.com/static/book/VCL_Basics.html#the-initial-value-of-beresp-ttl
  # Drupal's Imagecache module can return a 307 redirection to the requested url itself and, depending on Drupal's cache settings,
  # this could lead to a redirection loop being cached for a long time but also we want Varnish to shield a little the backend.
  # See http://drupal.org/node/1248010
  # See http://drupal.org/node/310656
  if (beresp.status == 307 &&
      #TODO# verify that this work better than 'bereq.url ~ "imagecache"' */
      beresp.http.Location == bereq.url &&
      beresp.ttl > 5s) {
    set beresp.ttl = 5s;
    set beresp.http.cache-control = "max-age=5";
  }

  /* Request retrial */
  if ( beresp.status == 500
    || beresp.status == 503
  ) {
    #TODO# consider not restarting POST requests as seenV3 on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
    return (retry);
  }

  /* Enable grace mode. Related with vcl_hit */
  # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
  set beresp.grace = 1h;

  /* Strip cookies from the following static file types for all users. Related with our 12th stage on vcl_recv */
  if (bereq.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|woff2|svg|pdf)(\?(itok=)?[a-z0-9_=\.\-]+)?$") {
    unset beresp.http.set-cookie;
  }

  /* Gzip response */
  # Empty in simple configs
  # Use Varnish to Gzip respone, if suitable, before storing it on cache
  # See https://www.varnish-cache.org/docs/4.0/users-guide/compression.html
  # See https://www.varnish-cache.org/docs/4.0/phk/gzip.html
  if ( ! beresp.http.Content-Encoding
    && ( beresp.http.content-type ~ "text"
      || beresp.http.content-type ~ "application/x-javascript"
      || beresp.http.content-type ~ "application/javascript"
      || beresp.http.content-type ~ "application/rss+xml"
      || beresp.http.content-type ~ "application/xml"
      || beresp.http.content-type ~ "Application/JSON")
  ) {
    set beresp.do_gzip = true;
  }

  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # We can add the name of the backend that has processed the request:
  # set beresp.http.X-Backend = beresp.backend.name;
  # We can use a header to tell if the object was gziped by Varnish
  # if (beresp.do_gzip) {
  #   set beresp.http.X-Varnish-Gzipped = "yes";
  # } else {
  #   set beresp.http.X-Varnish-Gizipped = "no";
  # }
  # We can also add headers informing whether the object is cacheable or not and why.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Varnish3.0
  if (beresp.ttl <= 0s) {
    /* Varnish determined the object was not cacheable */
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
  } elsif (bereq.http.Cookie ~ "(SESS|SSESS|NO_CACHE|OATMEAL|CHOCOLATECHIP)") {
    /* We don't wish to cache content for logged in users or with certain cookies. Related with our 9th stage on vcl_recv */
    set beresp.http.X-Cacheable = "NO:Cookies";
    # return(hit_for_pass);
  } elsif (beresp.http.Cache-Control ~ "private") {
    /* We are respecting the Cache-Control=private header from the backend */
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    # return(hit_for_pass);
  } else {
    /* Varnish determined the object was cacheable */
    set beresp.http.X-Cacheable = "YES";
  }

  /* Further header manipulation */
  # Empty in simple configs.
  # We can also unset some headers to prevent information disclosure and save some cache space
  # unset beresp.http.Server;
  # unset beresp.http.X-Powered-By;
  # Retry count
  if ( bereq.retries > 0) {
    set beresp.http.X-Retries = bereq.retries;
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_backend_response {
#     if (beresp.ttl <= 0s ||
#       beresp.http.Set-Cookie ||
#       beresp.http.Surrogate-control ~ "no-store" ||
#       (!beresp.http.Surrogate-Control &&
#         beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
#       beresp.http.Vary == "*") {
#         /*
#         * Mark as "Hit-For-Pass" for the next 2 minutes
#         */
#         set beresp.ttl = 120s;
#         set beresp.uncacheable = true;
#     }
#     return (deliver);
# }

# vcl_backend_error: This subroutine is called if we fail the backend fetch.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-backend-error
sub vcl_backend_error {

  /* Try to restart request in case of failure */
  #TODO# Confirm max_retries default value
  # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
  if (bereq.retries < 4) {
    return (retry);
  }

  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # Retry count
  if ( bereq.retries > 0) {
    set beresp.http.X-Retries = bereq.retries;
  }

  set beresp.http.Content-Type = "text/html; charset=utf-8";
  set beresp.http.Retry-After = "5";
  synthetic( {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + beresp.status + " " + beresp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + beresp.status + " " + beresp.reason + {"</h1>
    <p>"} + beresp.reason + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + bereq.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"} );

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  return (deliver);
}

#######################################################################
# Housekeeping

# vcl_init: Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-init
# Here is where you should declare your directors now.
# See https://www.varnish-cache.org/docs/4.0/reference/vmod_directors.generated.html
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-backends.html#directors
# Empty in simple configs
# sub vcl_init {
#     return (ok);
# }

# vcl_fini: Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-fini
# sub vcl_fini {
#     return (ok);
# }

/* Varnish 4 example config for Drupal 7 / Pressflow 6 & 7 */
# Original source: https://github.com/NITEMAN/varnish-bites/varnish4/drupal-base.vcl
# Copyright (c) 2015 Pedro González Serrano and individual contributors.
# MIT License

# Intended to be used both in simple production environments and with
# learning/teaching purposes.
# Some references may not be yet updated to VCL 4.0, we use SeeV3 then.

# WARNING:
# Note that the built-in logic will be appended to our code if no return is performed before.
# Built-in logic is included commented out right after our's for reference purposes in that cases.
# See https://www.varnish-cache.org/trac/wiki/VCLExampleDefault

#######################################################################
# Initialization: Version & imports;

/* Version statement */
# Since Varnish 4.0 it's mandatory to declare VCL version on first line.
vcl 4.0;

/* Module (VMOD) imports */
# Standard module
# See https://www.varnish-cache.org/docs/4.0/reference/vmod_std.generated.html
import std;

# Directors module
# See https://www.varnish-cache.org/docs/4.0/reference/vmod_directors.generated.html
# Unused in simple configs.
#import directors;

#######################################################################
# Probe, backend, ACL and subroutine definitions

/* Backend probes / healthchecks */
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#probes
probe basic {
  /* Only test that backend's IP serves content for '/' */
  # This might be a too heavy probe
  # .url = "/";
  /* Only test that backend's IP has apache working */
  # Nginx would fail this probe with a default config
  .request =
    "OPTIONS * HTTP/1.1"
    "Host: *"
    "Connection: close";
  .interval = 10s;
  .timeout = 2s;
  .window = 8;
  .threshold = 6;
}

/* Backend definitions.*/
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#backend-definition
backend default {
  /* Default backend on the same machine. WARNING: timeouts could be not big enought for certain POST request */
  .host = "127.0.0.1";
  .port = "8008";
  .connect_timeout = 60s;
  .first_byte_timeout = 60s;
  .between_bytes_timeout = 60s;
  .probe = basic;
}

/* Access Control Lists */
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#access-control-list-acl
acl purge_ban {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use '"localhost";' instead
}
acl allowed_monitors {
  /* Simple access control list for allowing item purge for the self machine */
  "127.0.0.1"/32; // We can use'"localhost";' instead
}
#acl own_proxys {
#  "127.0.0.1"/32; // We can use'"localhost";' instead
#}

/* Custom subroutines */
# See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#subroutines
#TODO# Test in Varnihs 4
# Empty in simple configs.
# We can name subs with no restrictions but as a task can need several chunks of code in diferent states,
# it's a good idea to identify what main sub will call each with a suffix.
# /* Example 301 client redirection removing "www" prefix from request */
# sub perm_redirections_recv {
#   if ( req.http.host ~ "^www.*$" ) {
#     return(synth(751, "http://" + regsub(req.http.host, "^www\.", "") + req.url));
#   }
# }
# sub perm_redirections_synth {
#   if (resp.status == 751) {
#     /* Get new URL from the response */
#     set resp.http.Location = resp.response;
#     /* Set HTTP 301 for permanent redirect */
#     set resp.status = 301;
#     return (deliver);
#   }
# }

#######################################################################
# Client side

# vcl_recv: Called at the beginning of a request, after the complete request has been received and parsed.
# Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, which backend to use.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-recv
sub vcl_recv {
  /* 0th: general bypass, general return & authorization checks */
  # Empty in simple configs.
  # Useful for debugging we can pipe or pass the request to default backend here to bypass completely Varnish.
  # return (pipe);
  # return (pass);
  # We can also return here a 200 Ok for network performance benchmarking.
  # return(synth(200, "Ok"));
  # Finally we can perform basic HTTP authentification here, by example.
  # SeeV3 http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* 1st: Check for Varnish special requests */
  # Custom response implementation example in order to check that Varnish is working properly.
  # This is usefull for automatic monitoring with monit or when Varnish is behind another proxies like HAProxy.
  if ( ( req.http.host == "monitor.server.health"
      || req.http.host == "health.varnish" )
    && client.ip ~ allowed_monitors
    && ( req.method == "OPTIONS" || req.method == "GET" )
  ) {
    return(synth(200, "Ban added"));
  }
  # Purge logic
  # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#http-purging
  # SeeV3 https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.method == "PURGE") {
    if (!client.ip ~ purge_ban) {
      return(synth(405, "Not allowed."));
    }
    return (purge);
  }
  # Ban logic
  # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#bans
  if (req.method == "BAN") {
    if (!client.ip ~ purge_ban) {
      return(synth(405, "Not allowed."));
    }
    ban("req.http.host == " + req.http.host +
      "&& req.url == " + req.url);
    return(synth(200, "Ban added"));
  }

  /* 2nd: Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_recv;
  # Here we can also enforce SSL when Varnish run behind some SSL termination point.

  /* 3rd: Time for backend choice */
  # Empty in simple configs.

  /* 4th: Prepare headers for the backend */
  # Empty in simple configs.
  # Example remove own_proxys from X-Forwarded-For
  # See https://www.varnish-cache.org/docs/4.0/whats-new/upgrading.html#x-forwarded-for-is-now-set-before-vcl-recv
  # if ( req.restarts == 0
  #   && client.ip ~ own_proxys
  #   && req.http.x-forwarded-for
  # ) {
  #   set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, ",( )?" + client.ip, "");
  # }

  /* 5th: Bypass breakpoint 1 */
  # Useful for debugging we can now pipe or pass the request to backend with headers setted.
  # return (pipe);
  # return (pass);

  /* 6th: Decide if we should deal with a request (mostly copied from built-in logic) */
  if (req.method == "PRI") {
    /* We do not support SPDY or HTTP/2.0 */
    return (synth(405));
  }
  if ( req.method != "GET"
    && req.method != "HEAD"
    && req.method != "PUT"
    && req.method != "POST"
    && req.method != "TRACE"
    && req.method != "OPTIONS"
    && req.method != "DELETE"
  ) {
    /* Non-RFC2616 or CONNECT which is weird. */
    return (pipe);
  }
  if (req.method != "GET" && req.method != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
  }
  if (req.http.Authorization) {
    /* Not cacheable by default */
    return (pass);
  }

  /* 7th: Access control for some URLs by ACL */
  # Empty in simple configs.
  # By example denial some URLs depending on client-ip, we'll need to define corresponding ACL 'internal'.
  # if ( req.url ~ "^/(cron|install)\.php"
  #   && ! client.ip ~ internal
  # ) {
  #   # Have Varnish throw the error directly.
  #   return(synth(403, "Forbidden."));
  #   # Use a custom error page that you've defined in Drupal at the path "404".
  #   # set req.url = "/403";
  # }

  /* 8th: Custom exceptions */
  # Host exception example:
  # if (req.http.host == "ejemplo.exception.com") {
  #     return (pass);
  # }
  # Drupal exceptions, edit if we want to cache some AJAX/AHAH request.
  # Add here filters for never cache URLs such as Payment Gateway's callbacks
  if (req.url ~ "^/status\.php$" ||
      req.url ~ "^/update\.php$" ||
      req.url ~ "^/ooyala/ping$" ||
      req.url ~ "^/admin/build/features" ||
      req.url ~ "^/info/.*$" ||
      req.url ~ "^/flag/.*$" ||
      req.url ~ "^.*/ajax/.*$" ||
      req.url ~ "^.*/ahah/.*$") {
    /* Do not cache these paths */
    return (pass);
  }
  # Pipe these paths directly to backend for streaming.
  if (req.url ~ "^/admin/content/backup_migrate/export") {
    return (pipe);
  }
  if (req.url ~ "^/system/files") {
    return (pipe);
  }

  /* 9th: Serve from anonymous cahe if all backends are down */
  if (! std.healthy(req.backend_hint) ) {
  #TODO# Consider moving this to vcl_backend_fetch
    unset req.http.Cookie;
    #TODO# Add sick marker
  }

  /* 10th: Deal with compression and the Accept-Encoding header */
  # Althought Varnish 3 handles gziped content itself by default, just to be sure we want to
  # remove Accept-Encoding for some compressed formats.
  # See https://www.varnish-cache.org/docs/4.0/phk/gzip.html#what-does-http-gzip-support-do
  # See https://www.varnish-cache.org/docs/4.0/users-guide/compression.html
  # See https://www.varnish-cache.org/docs/4.0/reference/varnishd.html?highlight=http_gzip_support
  # See (for older configs) https://www.varnish-cache.org/trac/wiki/VCLExampleNormalizeAcceptEncoding
  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|mp4|flv|zip|rar)$") {
      /* Already compressed formats, no sense trying to compress again */
      unset req.http.Accept-Encoding;
    }
  }

  /* 11th: Another header manipulation */
  # Empty in simple configs.
  # We could add here a custom header grouping User-agent families.

  /* 12th: Cookie removal */
  # Always cache the following static file types for all users.
  # Use with care if we control certain downloads depending on cookies.
  # Be carefull also if appending .htm[l] via Drupal's clean URLs.
  if ( req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|woff2|svg|pdf)(\?(itok=)?[a-z0-9_=\.\-]+)?$"
    && req.url !~ "/system/storage/serve"
  ) {
      unset req.http.Cookie;
  }
  # Remove all cookies that backend doesn't need to know about.
  # See https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
  if (req.http.Cookie) {
    /* Warning: Not a pretty solution */
    /* Prefix header containing cookies with ';' */
    set req.http.Cookie = ";" + req.http.Cookie;
    /* Remove any spaces after ';' in header containing cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    /* Prefix cookies we want to preserve with one space */
    /* 'S{1,2}ESS[a-z0-9]+' is the regular expression matching a Drupal session cookie ({1,2} added for HTTPS support) */
    /* 'NO_CACHE' is usually set after a POST request to make sure issuing user see the results of his post */
    /* 'OATMEAL' & 'CHOCOLATECHIP' are special cookies used by Drupal's Bakery module to provide Single Sign On */
    /* Keep in mind we should add here any cookie that should reach the backend such as splahs avoiding cookies */
    set req.http.Cookie = regsuball(req.http.Cookie, ";(S{1,2}ESS[a-z0-9]+|NO_CACHE|OATMEAL|CHOCOLATECHIP)=", "; \1=");
    /* Remove from the header any single Cookie not prefixed with a space until next ';' separator */
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    /* Remove any '; ' at the start or the end of the header */
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      /* If there are no remaining cookies, remove the cookie header. */
      unset req.http.Cookie;
    }
  }

  /* 13th: Session cookie & special cookies bypass caching stage */
  # As we might want to cache some requests, hashed with its cookies,
  # we don't simply pass when some cookies remain present at this point.
  # Instead we look for request that must be passed due to the cookie header.
  if ( req.http.Cookie ~ "SESS"
    || req.http.Cookie ~ "SSESS"
    || req.http.Cookie ~ "NO_CACHE"
    || req.http.Cookie ~ "OATMEAL"
    || req.http.Cookie ~ "CHOCOLATECHIP"
  ) {
    return (pass);
  }

  /* 14th: Bypass breakpoint 2 */
  # Useful for debugging we can now pipe or pass the request to backend to bypass cache.
  # return (pipe);
  # return (pass);

  /* 15th: Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning inconditionally.
  return (hash);
}

# vcl_pipe: Called upon entering pipe mode.
# In this mode, the request is passed on to the backend,
# and any further data from either client or backend is passed on unaltered until either end closes the connection.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-pipe
# sub vcl_pipe {
#     # By default Connection: close is set on all piped requests, to stop
#     # connection reuse from sending future requests directly to the
#     # (potentially) wrong backend. If you do want this to happen, you can undo
#     # it here.
#     # unset bereq.http.connection;
#     return (pipe);
# }

# vcl_pass: Called upon entering pass mode.
# In this mode, the request is passed on to the backend, and the backend's response is passed on to the client,
# but is not entered into the cache.
# Subsequent requests submitted over the same client connection are handled normally.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-pass
# sub vcl_pass {
#     return (fetch);
# }

# vcl_hash: You may call hash_data() on the data you would like to add to the hash.
# Hash is used by Varnish to uniquely identify objects.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-hash
sub vcl_hash {
  /* Hash cookie data */
  # As requests with same URL and host can produce diferent results when issued with different cookies,
  # we need to store items hashed with the associated cookies. Note that cookies are already sanitized when we reach this point.
  if (req.http.Cookie) {
    /* Include cookie in cache hash */
    hash_data(req.http.Cookie);
  }

  /* Custom header hashing */
  # Empty in simple configs.
  # Example for caching differents object versions by device previously detected (when static content could also vary):
  # if (req.http.X-UA-Device) {
  #   hash_data(req.http.X-UA-Device);
  # }
  # Example for caching diferent object versions by X-Forwarded-Proto, trying to be smart about what kind of request
  # could generate diffetent responses.
  if ( req.http.X-Forwarded-Proto
    && req.url !~ "(?i)\.(png|gif|jpeg|jpg|ico|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|woff2|svg|pdf)(\?(itok=)?[a-z0-9_=\.\-]+)?$") {
    hash_data(req.http.X-Forwarded-Proto);
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (lookup);
# }

# vcl_purge: Called after the purge has been executed and all its variants have been evited.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-purge
# sub vcl_purge {
#     return (synth(200, "Purged"));
# }

# vcl_hit: Called after a cache lookup if the requested document was found in the cache.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-hit
sub vcl_hit {
  if (obj.ttl >= 0s) {
    // A pure unadultered hit, deliver it
    return (deliver);
  }
  /* Allow varnish to serve up stale content if it is responding slowly */
  # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
  if (obj.ttl + 60s > 0s) {
    // Object is in grace, deliver it
    // Automatically triggers a background fetch
    return (deliver);
  }
  /* Allow varish to serve up stale content if all backends are down */
  # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
  if ( ! std.healthy(req.backend_hint)
    && obj.ttl + obj.grace > 0s
  ) {
    // Object is in grace, deliver it
    // Automatically triggers a background fetch
    return (deliver);
  }
  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning inconditionally.
  // fetch & deliver once we get the result
  return (fetch);
}

# vcl_miss: Called after a cache lookup if the requested document was not found in the cache.
# Its purpose is to decide whether or not to attempt to retrieve the document from the backend, and which backend to use.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-miss
# sub vcl_miss {
#     return (fetch);
# }

# vcl_deliver: Called before an object is delivered to the client
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-deliver
sub vcl_deliver {
  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # Add whether the object is a cache hit or miss and the number of hits for the object.
  # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
  # In Varnish 4 the obj.hits counter behaviour has changed (see bug 1492), so
  # we use a different method: if X-Varnish contains only 1 id, we have a miss,
  # if it contains more (and therefore a space), we have a hit.
  if (resp.http.x-varnish ~ " ") {
    set resp.http.X-Cache = "HIT";
    # Since in Varnish 4 the behaviour of obj.hits changed, this might not be accurate
    # See https://www.varnish-cache.org/trac/ticket/1492
    set resp.http.X-Cache-Hits = obj.hits;
  } else {
    set resp.http.X-Cache = "MISS";
    /* Show the results of cookie sanitization */
    set resp.http.X-Cookie = req.http.Cookie;
  }

  #TODO# Add sick marker

  # Restart count
  if ( req.restarts > 0) {
    set resp.http.X-Restarts = req.restarts;
  }

  # Add the Varnish server hostname
  set resp.http.X-Varnish-Server = server.hostname;
  # If we have setted a custom header with device family detected we can show it:
  # if (req.http.X-UA-Device) {
  #   set resp.http.X-UA-Device = req.http.X-UA-Device;
  # }
  # If we have recived a custom header with the protocol in the request we can show it:
  # if (req.http.X-Forwarded-Proto) {
  #   set resp.http.X-Forwarded-Proto = req.http.X-Forwarded-Proto;
  # }

  /* Vary header manipulation */
  # Empty in simple configs.
  # By example, if we are storing & serving diferent objects depending on User-Agent header we must set the correct Vary header:
  # if (resp.http.Vary) {
  #   set resp.http.Vary = resp.http.Vary + ",User-Agent";
  # } else {
  #   set resp.http.Vary = "User-Agent";
  # }

  /* Fake headers */
  # Empty in simple configs
  # We can fake server headers here, by example:
  # set resp.http.Server = "Deep thought";
  # set resp.http.X-Powered-By = "BOFH";
  # Or have some fun with headers:
  # See http://www.nextthing.org/archives/2005/08/07/fun-with-http-headers
  # See http://royal.pingdom.com/2012/08/15/fun-and-unusual-http-response-headers/
  # set resp.http.X-Thank-You = "for bothering to look at my HTTP headers";
  # set resp.http.X-Answer = "42";

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_deliver {
#     return (deliver);
# }

# vcl_synth: Called to deliver a synthetic object. A synthetic object is generated in VCL,
# not fetched from the backend. It is typically contructed using the synthetic() function.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-synth
/*
 * We can come here "invisibly" with the following errors: 413, 417 & 503
 */
sub vcl_synth {
  /* Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_synth;

  /* Try to restart request in case of failure */
  # Note that max_restarts defaults to 4
  # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
  if (resp.status == 503 && req.restarts < 4) {
    return(restart);
  }

  /* Set common headers for synthetic responses */
  set resp.http.Content-Type = "text/html; charset=utf-8";

  /* HTTP Authentification client request */
  # Empty in simple configs. SeeV3 http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* Error page & refresh / redirections */
  # We have plenty of choices when we have to serve an error to the client,
  # from the default error page to javascript black magic or plain redirections.
  # Adding some external statistic javascript to track failures served to clients is strongly suggested.
  # We can't use external resources on synthetic content, everything must be inlined.
  # If we need to include images we can embed them in base64 encoding.
  # Here is the default error page for Varnish 4 (not so pretty)
  # We're using error 200 for monitoring puposes which should not be retried client side */
  if ( resp.status != 200) {
    set resp.http.Retry-After = "5";
  }

  ## Example custom 403 error page.
  #if (resp.status == 403) {
  #  synthetic(std.fileread("/403.html"));
  #  return(deliver);
  #}

  # Consider add some analytics stuff to trace accesses
  synthetic( {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + resp.status + " " + resp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + resp.status + " " + resp.reason + {"</h1>
    <p>"} + resp.reason + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"} );

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning inconditionally.
  return (deliver);
}

#######################################################################
# Backend Fetch

# vcl_backend_fetch: Called before sending the backend request. In this subroutine you typically alter the request before it gets to the backend.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-backend-fetch
# sub vcl_backend_fetch {
#     return (fetch);
# }

# vcl_backend_response: Called after the response headers has been successfully retrieved from the backend.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-backend-response
sub vcl_backend_response {
  /* Caching exceptions */
  # Varnish will cache objects with response codes: 200, 203, 300, 301, 302, 307, 404 & 410.
  # SeeV3 https://www.varnish-software.com/static/book/VCL_Basics.html#the-initial-value-of-beresp-ttl
  # Drupal's Imagecache module can return a 307 redirection to the requested url itself and, depending on Drupal's cache settings,
  # this could lead to a redirection loop being cached for a long time but also we want Varnish to shield a little the backend.
  # See http://drupal.org/node/1248010
  # See http://drupal.org/node/310656
  if (beresp.status == 307 &&
      #TODO# verify that this work better than 'bereq.url ~ "imagecache"' */
      beresp.http.Location == bereq.url &&
      beresp.ttl > 5s) {
    set beresp.ttl = 5s;
    set beresp.http.cache-control = "max-age=5";
  }

  /* Request retrial */
  if ( beresp.status == 500
    || beresp.status == 503
  ) {
    #TODO# consider not restarting POST requests as seenV3 on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
    return (retry);
  }

  /* Enable grace mode. Related with vcl_hit */
  # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
  set beresp.grace = 1h;

  /* Strip cookies from the following static file types for all users. Related with our 12th stage on vcl_recv */
  if (bereq.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|zip|rar|otf|ttf|eot|woff|woff2|svg|pdf)(\?(itok=)?[a-z0-9_=\.\-]+)?$") {
    unset beresp.http.set-cookie;
  }

  /* Gzip response */
  # Empty in simple configs
  # Use Varnish to Gzip respone, if suitable, before storing it on cache
  # See https://www.varnish-cache.org/docs/4.0/users-guide/compression.html
  # See https://www.varnish-cache.org/docs/4.0/phk/gzip.html
  if ( ! beresp.http.Content-Encoding
    && ( beresp.http.content-type ~ "text"
      || beresp.http.content-type ~ "application/x-javascript"
      || beresp.http.content-type ~ "application/javascript"
      || beresp.http.content-type ~ "application/rss+xml"
      || beresp.http.content-type ~ "application/xml"
      || beresp.http.content-type ~ "Application/JSON")
  ) {
    set beresp.do_gzip = true;
  }

  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # We can add the name of the backend that has processed the request:
  # set beresp.http.X-Backend = beresp.backend.name;
  # We can use a header to tell if the object was gziped by Varnish
  # if (beresp.do_gzip) {
  #   set beresp.http.X-Varnish-Gzipped = "yes";
  # } else {
  #   set beresp.http.X-Varnish-Gizipped = "no";
  # }
  # We can also add headers informing whether the object is cacheable or not and why.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Varnish3.0
  if (beresp.ttl <= 0s) {
    /* Varnish determined the object was not cacheable */
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
  } elsif (bereq.http.Cookie ~ "(SESS|SSESS|NO_CACHE|OATMEAL|CHOCOLATECHIP)") {
    /* We don't wish to cache content for logged in users or with certain cookies. Related with our 9th stage on vcl_recv */
    set beresp.http.X-Cacheable = "NO:Cookies";
    # return(hit_for_pass);
  } elsif (beresp.http.Cache-Control ~ "private") {
    /* We are respecting the Cache-Control=private header from the backend */
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    # return(hit_for_pass);
  } else {
    /* Varnish determined the object was cacheable */
    set beresp.http.X-Cacheable = "YES";
  }

  /* Further header manipulation */
  # Empty in simple configs.
  # We can also unset some headers to prevent information disclosure and save some cache space
  # unset beresp.http.Server;
  # unset beresp.http.X-Powered-By;
  # Retry count
  if ( bereq.retries > 0) {
    set beresp.http.X-Retries = bereq.retries;
  }

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# sub vcl_backend_response {
#     if (beresp.ttl <= 0s ||
#       beresp.http.Set-Cookie ||
#       beresp.http.Surrogate-control ~ "no-store" ||
#       (!beresp.http.Surrogate-Control &&
#         beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
#       beresp.http.Vary == "*") {
#         /*
#         * Mark as "Hit-For-Pass" for the next 2 minutes
#         */
#         set beresp.ttl = 120s;
#         set beresp.uncacheable = true;
#     }
#     return (deliver);
# }

# vcl_backend_error: This subroutine is called if we fail the backend fetch.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-backend-error
sub vcl_backend_error {

  /* Try to restart request in case of failure */
  #TODO# Confirm max_retries default value
  # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
  if (bereq.retries < 4) {
    return (retry);
  }

  /* Debugging headers */
  # Please consider the risks of showing publicly this information, we can wrap this with an ACL
  # Retry count
  if ( bereq.retries > 0) {
    set beresp.http.X-Retries = bereq.retries;
  }

  set beresp.http.Content-Type = "text/html; charset=utf-8";
  set beresp.http.Retry-After = "5";
  synthetic( {"<!DOCTYPE html>
<html>
  <head>
    <title>"} + beresp.status + " " + beresp.reason + {"</title>
  </head>
  <body>
    <h1>Error "} + beresp.status + " " + beresp.reason + {"</h1>
    <p>"} + beresp.reason + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + bereq.xid + {"</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
"} );

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  return (deliver);
}

#######################################################################
# Housekeeping

# vcl_init: Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-init
# Here is where you should declare your directors now.
# See https://www.varnish-cache.org/docs/4.0/reference/vmod_directors.generated.html
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-backends.html#directors
# Empty in simple configs
# sub vcl_init {
#     return (ok);
# }

# vcl_fini: Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.
# See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-built-in-subs.html#vcl-fini
# sub vcl_fini {
#     return (ok);
# }


Remove unused piece of VCL

Remove unused piece of VCL

backend default {
    .host = "localhost";
    .port = "8000";
}

acl invalidators {
    "localhost";
}

sub vcl_recv {
    if (req.request == "PURGE") {
        if (!client.ip ~ invalidators) {
            error 405 "Not allowed";
        }
        return (lookup);
    }

    if (req.request == "BAN") {
        if (!client.ip ~ invalidators) {
            error 405 "Not allowed.";
        }

        if (req.http.x-cache-tags) {
            ban("obj.http.host ~ " + req.http.x-host
                + " && obj.http.x-url ~ " + req.http.x-url
                + " && obj.http.content-type ~ " + req.http.x-content-type
                + " && obj.http.x-cache-tags ~ " + req.http.x-cache-tags
            );
        } else {
            ban("obj.http.host ~ " + req.http.x-host
                + " && obj.http.x-url ~ " + req.http.x-url
                + " && obj.http.content-type ~ " + req.http.x-content-type
            );
        }

        error 200 "Banned";
    }
}

sub vcl_fetch {

    # Set ban-lurker friendly custom headers
    set beresp.http.x-url = req.url;
    set beresp.http.x-host = req.http.host;
}

sub vcl_hit {
    if (req.request == "PURGE") {
        purge;
        error 200 "Purged";
    }
}

sub vcl_miss {
    if (req.request == "PURGE") {
        purge;
        error 404 "Not in cache";
    }
}

sub vcl_deliver {
    # Add extra headers if debugging is enabled
    if (resp.http.x-cache-debug) {
        if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT";
        } else {
            set resp.http.X-Cache = "MISS";
        }
    } else {
        # Remove ban-lurker friendly custom headers when delivering to client
        unset resp.http.x-url;
        unset resp.http.x-host;
    }
}

backend default {
    .host = "localhost";
    .port = "8000";
}

acl invalidators {
    "localhost";
}

sub vcl_recv {
    if (req.request == "PURGE") {
        if (!client.ip ~ invalidators) {
            error 405 "Not allowed";
        }
        return (lookup);
    }

    if (req.request == "BAN") {
        if (!client.ip ~ invalidators) {
            error 405 "Not allowed.";
        }

        if (req.http.x-cache-tags) {
            ban("obj.http.host ~ " + req.http.x-host
                + " && obj.http.x-url ~ " + req.http.x-url
                + " && obj.http.content-type ~ " + req.http.x-content-type
                + " && obj.http.x-cache-tags ~ " + req.http.x-cache-tags
            );
        } else {
            ban("obj.http.host ~ " + req.http.x-host
                + " && obj.http.x-url ~ " + req.http.x-url
                + " && obj.http.content-type ~ " + req.http.x-content-type
            );
        }

        error 200 "Banned";
    }
}

sub vcl_fetch {

    # Set ban-lurker friendly custom headers
    set beresp.http.x-url = req.url;
    set beresp.http.x-host = req.http.host;

    # Ban cache tags
    if (beresp.status >= 200 && beresp.status < 400
        && (req.request == "PUT" || req.request == "POST" || req.request == "PATCH" || req.request == "DELETE")
    ) {
        ban("obj.http.x-cache-tags ~ " + beresp.http.x-cache-tags);
    }
}

sub vcl_hit {
    if (req.request == "PURGE") {
        purge;
        error 200 "Purged";
    }
}

sub vcl_miss {
    if (req.request == "PURGE") {
        purge;
        error 404 "Not in cache";
    }
}

sub vcl_deliver {
    # Add extra headers if debugging is enabled
    if (resp.http.x-cache-debug) {
        if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT";
        } else {
            set resp.http.X-Cache = "MISS";
        }
    } else {
        # Remove ban-lurker friendly custom headers when delivering to client
        unset resp.http.x-url;
        unset resp.http.x-host;
    }
}


Probably best to still pass wp-login requests, and only pipe wp-admin reqs

# Pass all login requests straight through
if (req.url ~ "wp-login") {
    return (pass);
}
# Pipe all admin requests directly
if (req.url ~ "wp-admin") {
    return (pipe);
}

# Pass all requests containing a wp- or wordpress_ cookie
# (meaning NO caching for logged in users)
if (req.http.Cookie ~ "^([^;]+;\s*)*?(wp-|wordpress_)") {
  return (pass);
}

# Drop *all* cookies sent to Wordpress, if we've gotten this far
unset req.http.Cookie;

# Try a cache-lookup
return (lookup);

# Pass all login/admin requests straight through
if (req.url ~ "wp-(login|admin)") {
    return (pipe);
}

# Pass all requests containing a wp- or wordpress_ cookie
# (meaning NO caching for logged in users)
if (req.http.Cookie ~ "^([^;]+;\s*)*?(wp-|wordpress_)") {
  return (pass);
}

# Drop *all* cookies sent to Wordpress, if we've gotten this far
unset req.http.Cookie;

# Try a cache-lookup
return (lookup);


Pipe all requests for wp-login or wp-admin

This appears necessary for the web ui installs/updates to work. Should fix #30, and may fix #34 as well!

# Pass all login/admin requests straight through
if (req.url ~ "wp-(login|admin)") {
    return (pipe);
}

# Pass all requests containing a wp- or wordpress_ cookie
# (meaning NO caching for logged in users)
if (req.http.Cookie ~ "^([^;]+;\s*)*?(wp-|wordpress_)") {
  return (pass);
}

# Drop *all* cookies sent to Wordpress, if we've gotten this far
unset req.http.Cookie;

# Try a cache-lookup
return (lookup);

# Pass all login/admin requests straight through
if (req.url ~ "wp-(login|admin)") {
    return (pass);
}

# Pass all requests containing a wp- or wordpress_ cookie
# (meaning NO caching for logged in users)
if (req.http.Cookie ~ "^([^;]+;\s*)*?(wp-|wordpress_)") {
  return (pass);
}

# Drop *all* cookies sent to Wordpress, if we've gotten this far
unset req.http.Cookie;

# Try a cache-lookup
return (lookup);


Fix duplicate wording in example.vcl

Fix duplicate wording in example.vcl

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    # Happens before we check if we have this in cache already.
    #
    # Typically you clean up the request here, removing cookies you don't need,
    # rewriting the request, etc.
}

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
}

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.
}

#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the builtin vcl.
# The builtin VCL is called when there is no explicit explicit return
# statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    # Happens before we check if we have this in cache already.
    #
    # Typically you clean up the request here, removing cookies you don't need,
    # rewriting the request, etc.
}

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.
}

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.
}


flip the check over

flip the check over

import boltsort;

sub vcl_recv {
#FASTLY recv
	if ( req.request == "FASTLYPURGE" ) {
		set req.http.Fastly-Purge-Requires-Auth = "1";
	}

	if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
		return(pass);
	}

	if (!req.http.Fastly-SSL) {
		if (req.http.Host == "cdn.polyfill.io" || req.http.Host == "polyfill.io") {
			error 751 "Redirect to prod HTTPS";
		}
		if (req.http.Host == "qa.polyfill.io") {
			error 752 "Redirect to QA HTTPS";
		}
	}

	if (req.http.Host ~ "polyfills.io") {
		error 751 "Canonicalise";
	}

	if (req.url ~ "^/v2/(polyfill\.|recordRumData)" && req.url !~ "[\?\&]ua=") {
		set req.http.X-Orig-URL = req.url;
		set req.url = "/v2/normalizeUa?ua=" urlencode(req.http.User-Agent);
	}

	if (req.url ~ "^/v2/recordRumData" && req.http.Normalized-User-Agent) {
		set req.http.Log = regsub(req.url, "^.*?\?(.*)$", "\1") "&ip=" client.ip "&refer_domain=" regsub(req.http.Referer, "^(https?\:\/\/)?(www\.)?(.+?)(\:\d+)?([\/\?].*)?$", "\3") "&country=" geoip.country_code "&data_center=" if(req.http.Cookie:FastlyDC, req.http.Cookie:FastlyDC, server.datacenter);
		error 204 "No Content";
	}

	set req.url = boltsort.sort(req.url);

	return(lookup);
}

sub vcl_deliver {
#FASTLY deliver

	# If the response is to a normalise request and there's a parked "original request", use the normalised UA response to modify the original request and restart it
	if (req.url ~ "^/v\d/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL ~ "^/v2/(polyfill\.|recordRumData)") {
		set req.http.Fastly-force-Shield = "1";
		set req.http.Normalized-User-Agent = resp.http.Normalized-User-Agent;
		if (req.http.X-Orig-URL ~ "\?") {
			set req.url = req.http.X-Orig-URL "&ua=" resp.http.Normalized-User-Agent;
		} else {
			set req.url = req.http.X-Orig-URL "?ua=" resp.http.Normalized-User-Agent;
		}
		restart;

	# If the original request didn't specify a UA override, and we added one when the request was sent to the backend, the backend won't have included a Vary:user-agent header (correctly) but we need to add one
	} else if (req.url ~ "^/v\d/polyfill\..*[\?\&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[\?\&]ua=") {
		add resp.http.Vary = "User-Agent";
	}

	if (req.url ~ "[\&\?]rum=1") {
		add resp.http.Set-Cookie = "FastlyDC=" server.datacenter "; Path=/; HttpOnly; max-age=60";
	}

	return(deliver);
}

sub vcl_error {

	# Redirect to canonical prod/qa origins
	if (obj.status == 751 || obj.status == 752) {
		set obj.status = 301;
		set obj.response = "Moved Permanently";
		set obj.http.Location = "https://" if(obj.status == 751, "", "qa.") "polyfill.io" req.url;
		synthetic {""};
		return (deliver);
	}
}

import boltsort;

sub vcl_recv {
#FASTLY recv
	if ( req.request == "FASTLYPURGE" ) {
		set req.http.Fastly-Purge-Requires-Auth = "1";
	}

	if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
		return(pass);
	}

	if (!req.http.Fastly-SSL) {
		if (req.http.Host == "cdn.polyfill.io" || req.http.Host == "polyfill.io") {
			error 751 "Redirect to prod HTTPS";
		}
		if (req.http.Host == "qa.polyfill.io") {
			error 752 "Redirect to QA HTTPS";
		}
	}

	if (req.http.Host ~ "polyfills.io") {
		error 751 "Canonicalise";
	}

	if (req.url ~ "^/v2/(polyfill\.|recordRumData)" && req.url !~ "[\?\&]ua=") {
		set req.http.X-Orig-URL = req.url;
		set req.url = "/v2/normalizeUa?ua=" urlencode(req.http.User-Agent);
	}

	if (req.url ~ "^/v2/recordRumData" && req.http.Normalized-User-Agent) {
		set req.http.Log = regsub(req.url, "^.*?\?(.*)$", "\1") "&ip=" client.ip "&refer_domain=" regsub(req.http.Referer, "^(https?\:\/\/)?(www\.)?(.+?)(\:\d+)?([\/\?].*)?$", "\3") "&country=" geoip.country_code "&data_center=" if(req.http.Cookie:FastlyDC, req.http.Cookie:FastlyDC, server.datacenter);
		error 204 "No Content";
	}

	set req.url = boltsort.sort(req.url);

	return(lookup);
}

sub vcl_deliver {
#FASTLY deliver

	# If the response is to a normalise request and there's a parked "original request", use the normalised UA response to modify the original request and restart it
	if (req.url ~ "^/v\d/normalizeUa" && resp.status == 200 && req.http.X-Orig-URL ~ "^/v2/(polyfill\.|recordRumData)") {
		set req.http.Fastly-force-Shield = "1";
		set req.http.Normalized-User-Agent = resp.http.Normalized-User-Agent;
		if (req.http.X-Orig-URL ~ "\?") {
			set req.url = req.http.X-Orig-URL "&ua=" resp.http.Normalized-User-Agent;
		} else {
			set req.url = req.http.X-Orig-URL "?ua=" resp.http.Normalized-User-Agent;
		}
		restart;

	# If the original request didn't specify a UA override, and we added one when the request was sent to the backend, the backend won't have included a Vary:user-agent header (correctly) but we need to add one
	} else if (req.url ~ "^/v\d/polyfill\..*[\?\&]ua=" && req.http.X-Orig-URL && req.http.X-Orig-URL !~ "[\?\&]ua=") {
		add resp.http.Vary = "User-Agent";
	}

	if (req.url ~ "[\&\?]rum=1") {
		add resp.http.Set-Cookie = "FastlyDC=" server.datacenter "; Path=/; HttpOnly; max-age=60";
	}

	return(deliver);
}

sub vcl_error {

	# Redirect to canonical prod/qa origins
	if (obj.status == 751 || obj.status == 752) {
		set obj.status = 301;
		set obj.response = "Moved Permanently";
		set obj.http.Location = "https://" if(obj.status == 752, "qa.", "") "polyfill.io" req.url;
		synthetic {""};
		return (deliver);
	}
}


Add webp and svg to list of static assets

    # Fixup for Varnish ESI not dealing with https:// absolute URLs well
    if (req.is_esi_subreq && req.url ~ "/https://([^/]+)(/.*)$") {
        set req.http.Host = re.group.1;
        set req.url = re.group.2;
    }

    # Sort the query arguments
    set req.url = boltsort.sort(req.url);

    # bypass language switcher
    if (req.url ~ "(?i)___from_store=.*&___store=.*") {
        set req.http.X-Pass = "1";
    }

    # set HTTPS header for offloaded TLS
    if (req.http.Fastly-SSL) {
        set req.http.Https = "on";
    }

    if (req.http.cookie:FASTLY_CDN_ENV) {
        set req.http.Fastly-Cdn-Env = req.http.cookie:FASTLY_CDN_ENV;
    } else {
        unset req.http.Fastly-Cdn-Env;
    }

    # auth for purging
    if (req.request == "FASTLYPURGE") {

        if (!req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) {
            error 403;
        }

        declare local var.X-Exp STRING;
        declare local var.X-Sig STRING;
        /* extract token expiration and signature */
        set var.X-Exp = re.group.1;
        set var.X-Sig = re.group.2;

        /* validate signature */
        if (var.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path var.X-Exp), "^0x", "")) {
            /* check that expiration time has not elapsed */
            if (time.is_after(now, std.integer2time(std.atoi(var.X-Exp)))) {
                error 410;
            }

        } else {
            error 403;
        }

    }

    # disable ESI processing on Origin Shield
    if (req.http.Fastly-FF) {
        set req.esi = false;
        # Needed for proper handling of stale while revalidated when shielding is involved
        set req.max_stale_while_revalidate = 0s;
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico|webp|svg)$") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # formkey lookup
    if (req.url ~ "/fastlycdn/getformkey/") {
        # check if we have a formkey cookie
        if (req.http.Cookie:FASTLY_CDN_FORMKEY) {
            set req.http.Formkey = req.http.Cookie:FASTLY_CDN_FORMKEY;
        } else {
            # create formkey
            set req.http.seed = req.http.Cookie client.ip remote.port client.geo.longitude client.geo.latitude client.geo.postal_code;
            set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", "");
        }
        error 760 req.http.Formkey;
    }

    # client.geo lookup
    if (req.url ~ "fastlycdn/esi/getcountry/") {
        # check if GeoIP has been already processed by client
        if (req.http.Cookie:FASTLY_CDN_GEOIP_PROCESSED) {
            error 200 "";
        } else {
            # modify req.url and restart request processing
            error 750 client.geo.country_code;
        }
    }

    # client.geo get country code
    if (req.url ~ "fastlycdn/esi/getcountrycode/") {
        # create and set req.http.X-Country-Code
        error 755 client.geo.country_code;
    }

    # check for ESI calls
    if (req.url ~ "esi_data=") {
        # check for valid cookie data
        if (req.http.Cookie ~ "FASTLY_CDN-([A-Za-z0-9-_]+)=([^;]*)") {
            set req.url = querystring.filter(req.url, "esi_data") + "&esi_data=" + re.group.2;
        }
    }

    # Per suggestions in https://github.com/sdinteractive/SomethingDigital_PageCacheParams
    # we'll strip out query parameters used in Google AdWords, Mailchimp tracking
    set req.http.Magento-Original-URL = req.url;
    set req.url = querystring.regfilter(req.url, "^(utm_.*|gclid|gdftrk|_ga|mc_.*)");

    # Fixup for Varnish ESI not dealing with https:// absolute URLs well
    if (req.is_esi_subreq && req.url ~ "/https://([^/]+)(/.*)$") {
        set req.http.Host = re.group.1;
        set req.url = re.group.2;
    }

    # Sort the query arguments
    set req.url = boltsort.sort(req.url);

    # bypass language switcher
    if (req.url ~ "(?i)___from_store=.*&___store=.*") {
        set req.http.X-Pass = "1";
    }

    # set HTTPS header for offloaded TLS
    if (req.http.Fastly-SSL) {
        set req.http.Https = "on";
    }

    if (req.http.cookie:FASTLY_CDN_ENV) {
        set req.http.Fastly-Cdn-Env = req.http.cookie:FASTLY_CDN_ENV;
    } else {
        unset req.http.Fastly-Cdn-Env;
    }

    # auth for purging
    if (req.request == "FASTLYPURGE") {

        if (!req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) {
            error 403;
        }

        declare local var.X-Exp STRING;
        declare local var.X-Sig STRING;
        /* extract token expiration and signature */
        set var.X-Exp = re.group.1;
        set var.X-Sig = re.group.2;

        /* validate signature */
        if (var.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path var.X-Exp), "^0x", "")) {
            /* check that expiration time has not elapsed */
            if (time.is_after(now, std.integer2time(std.atoi(var.X-Exp)))) {
                error 410;
            }

        } else {
            error 403;
        }

    }

    # disable ESI processing on Origin Shield
    if (req.http.Fastly-FF) {
        set req.esi = false;
        # Needed for proper handling of stale while revalidated when shielding is involved
        set req.max_stale_while_revalidate = 0s;
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # formkey lookup
    if (req.url ~ "/fastlycdn/getformkey/") {
        # check if we have a formkey cookie
        if (req.http.Cookie:FASTLY_CDN_FORMKEY) {
            set req.http.Formkey = req.http.Cookie:FASTLY_CDN_FORMKEY;
        } else {
            # create formkey
            set req.http.seed = req.http.Cookie client.ip remote.port client.geo.longitude client.geo.latitude client.geo.postal_code;
            set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", "");
        }
        error 760 req.http.Formkey;
    }

    # client.geo lookup
    if (req.url ~ "fastlycdn/esi/getcountry/") {
        # check if GeoIP has been already processed by client
        if (req.http.Cookie:FASTLY_CDN_GEOIP_PROCESSED) {
            error 200 "";
        } else {
            # modify req.url and restart request processing
            error 750 client.geo.country_code;
        }
    }

    # client.geo get country code
    if (req.url ~ "fastlycdn/esi/getcountrycode/") {
        # create and set req.http.X-Country-Code
        error 755 client.geo.country_code;
    }

    # check for ESI calls
    if (req.url ~ "esi_data=") {
        # check for valid cookie data
        if (req.http.Cookie ~ "FASTLY_CDN-([A-Za-z0-9-_]+)=([^;]*)") {
            set req.url = querystring.filter(req.url, "esi_data") + "&esi_data=" + re.group.2;
        }
    }

    # Per suggestions in https://github.com/sdinteractive/SomethingDigital_PageCacheParams
    # we'll strip out query parameters used in Google AdWords, Mailchimp tracking
    set req.http.Magento-Original-URL = req.url;
    set req.url = querystring.regfilter(req.url, "^(utm_.*|gclid|gdftrk|_ga|mc_.*)");


Use secure string comparison to protect against timing attack

table consumer_secrets {
	"foo": "foo_secret"
}

table access_tokens {
	"bar": "bar_secret"
}

sub vcl_recv {
#FASTLY recv
#DEPLOY recv
	declare local var.consumer_key STRING;
	declare local var.consumer_secret STRING;
	declare local var.access_token STRING;
	declare local var.access_token_secret STRING;
	declare local var.provided_signature STRING;
	declare local var.parameters STRING;
	declare local var.base_string_uri STRING;
	declare local var.base_string STRING;
	declare local var.calculated_signature STRING;
	declare local var.timestamp STRING;

	set var.consumer_key = if(req.url ~ "(?i)oauth_consumer_key=([^&]*)",
			urldecode(re.group.1), "");
	if(var.consumer_key == "") {
		error 401 "Missing Consumer Key";
	}
	set var.consumer_secret = table.lookup(consumer_secrets, var.consumer_key, "");
	if(var.consumer_secret == "") {
		error 401 "Invalid Consumer Key";
	}
	set var.access_token = if(req.url ~ "(?i)oauth_token=([^&]*)",
			urldecode(re.group.1), "");
	if(var.access_token != "") {
		set var.access_token_secret = table.lookup(access_tokens, var.access_token, "");
		if(var.access_token_secret == "") {
			error 401 "Invalid Access Token";
		}
	} else {
		set var.access_token_secret = "";
	}
	set var.provided_signature = if(req.url ~ "(?i)oauth_signature=([^&]*)",
			urldecode(re.group.1), "");
	if(var.provided_signature == "") {
		error 401 "Missing Signature";
	}
	set var.parameters = regsub(
			regsub(boltsort.sort(req.url), ".*\?", ""),
			"&oauth_signature=[^&]*", "");
	set var.base_string_uri =
		if(req.http.Fastly-SSL, "https", "http")
			"://"
				std.tolower(req.http.host)
				req.url.path;
	set var.base_string =
		req.request
		"&"
		urlencode(var.base_string_uri)
		"&"
		urlencode(var.parameters);

	set var.calculated_signature = digest.hmac_sha1_base64(
			var.consumer_secret "&" var.access_token_secret,
			var.base_string);

	if(!digest.secure_is_equal(var.provided_signature,
			var.calculated_signature)) {
		error 401 "Invalid OAuth Signature";
	}

	set var.timestamp = if(req.url ~ "(?i)oauth_timestamp=([0-9]*)",
			urldecode(re.group.1), "");
	if(var.timestamp == "") {
		error 401 "Missing/Invalid Timestamp";
	}

	if(time.is_after(
				now,
				time.add(std.integer2time(std.atoi(var.timestamp)), 30m))) {
		error 401 "Timestamp expired";
	}

	if(time.is_after(
				std.integer2time(std.atoi(var.timestamp)),
				time.add(now, 1m))) {
		error 401 "Timestamp too far in future";
	}

	error 200 "Authenticated!";

	return(lookup);
}

sub vcl_fetch {
#FASTLY fetch
	return(deliver);
}

sub vcl_hit {
#FASTLY hit
	if (!obj.cacheable) {
		return(pass);
	}
	return(deliver);
}

sub vcl_miss {
#FASTLY miss
	return(fetch);
}

sub vcl_deliver{
#FASTLY deliver
	return(deliver);
}

sub vcl_error {
#FASTLY error
#DEPLOY error
}

sub vcl_pass {
#FASTLY pass
}

table consumer_secrets {
	"foo": "foo_secret"
}

table access_tokens {
	"bar": "bar_secret"
}

sub vcl_recv {
#FASTLY recv
#DEPLOY recv
	declare local var.consumer_key STRING;
	declare local var.consumer_secret STRING;
	declare local var.access_token STRING;
	declare local var.access_token_secret STRING;
	declare local var.provided_signature STRING;
	declare local var.parameters STRING;
	declare local var.base_string_uri STRING;
	declare local var.base_string STRING;
	declare local var.calculated_signature STRING;
	declare local var.timestamp STRING;

	set var.consumer_key = if(req.url ~ "(?i)oauth_consumer_key=([^&]*)",
			urldecode(re.group.1), "");
	if(var.consumer_key == "") {
		error 401 "Missing Consumer Key";
	}
	set var.consumer_secret = table.lookup(consumer_secrets, var.consumer_key, "");
	if(var.consumer_secret == "") {
		error 401 "Invalid Consumer Key";
	}
	set var.access_token = if(req.url ~ "(?i)oauth_token=([^&]*)",
			urldecode(re.group.1), "");
	if(var.access_token != "") {
		set var.access_token_secret = table.lookup(access_tokens, var.access_token, "");
		if(var.access_token_secret == "") {
			error 401 "Invalid Access Token";
		}
	} else {
		set var.access_token_secret = "";
	}
	set var.provided_signature = if(req.url ~ "(?i)oauth_signature=([^&]*)",
			urldecode(re.group.1), "");
	if(var.provided_signature == "") {
		error 401 "Missing Signature";
	}
	set var.parameters = regsub(
			regsub(boltsort.sort(req.url), ".*\?", ""),
			"&oauth_signature=[^&]*", "");
	set var.base_string_uri =
		if(req.http.Fastly-SSL, "https", "http")
			"://"
				std.tolower(req.http.host)
				req.url.path;
	set var.base_string =
		req.request
		"&"
		urlencode(var.base_string_uri)
		"&"
		urlencode(var.parameters);

	set var.calculated_signature = digest.hmac_sha1_base64(
			var.consumer_secret "&" var.access_token_secret,
			var.base_string);

	if(var.provided_signature != var.calculated_signature) {
		error 401 "Invalid OAuth Signature";
	}

	set var.timestamp = if(req.url ~ "(?i)oauth_timestamp=([0-9]*)",
			urldecode(re.group.1), "");
	if(var.timestamp == "") {
		error 401 "Missing/Invalid Timestamp";
	}

	if(time.is_after(
				now,
				time.add(std.integer2time(std.atoi(var.timestamp)), 30m))) {
		error 401 "Timestamp expired";
	}

	if(time.is_after(
				std.integer2time(std.atoi(var.timestamp)),
				time.add(now, 1m))) {
		error 401 "Timestamp too far in future";
	}

	error 200 "Authenticated!";

	return(lookup);
}

sub vcl_fetch {
#FASTLY fetch
	return(deliver);
}

sub vcl_hit {
#FASTLY hit
	if (!obj.cacheable) {
		return(pass);
	}
	return(deliver);
}

sub vcl_miss {
#FASTLY miss
	return(fetch);
}

sub vcl_deliver{
#FASTLY deliver
	return(deliver);
}

sub vcl_error {
#FASTLY error
#DEPLOY error
}

sub vcl_pass {
#FASTLY pass
}


new line at end of file

new line at end of file

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

import authentication;

sub vcl_recv {
	if(!authentication.match("admin", "test")) {
		error 401 "Authentication Required";
	}

	return (lookup);
}

sub vcl_error {
	if(obj.status == 401) {
		set obj.http.WWW-Authenticate = "Basic realm=Secure Area";
	}
}

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
backend default {
    .host = "127.0.0.1";
    .port = "80";
}

import authentication;

sub vcl_recv {
	if(!authentication.match("admin", "test")) {
		error 401 "Authentication Required";
	}

	return (lookup);
}

sub vcl_error {
	if(obj.status == 401) {
		set obj.http.WWW-Authenticate = "Basic realm=Secure Area";
	}
}


Adding X-Cache header in varnish VCL

Adding X-Cache header in varnish VCL

backend default {
  .host = "127.0.0.1";
  .port = "9090";
}

sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
  }
  else {
    set resp.http.X-Cache = "MISS";
  }
}

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
backend default {
  .host = "127.0.0.1";
  .port = "9090";
}
#
# Below is a commented-out copy of the default VCL logic.  If you
# redefine any of these subroutines, the built-in logic will be
# appended to your code.
# sub vcl_recv {
#     if (req.restarts == 0) {
# 	if (req.http.x-forwarded-for) {
# 	    set req.http.X-Forwarded-For =
# 		req.http.X-Forwarded-For + ", " + client.ip;
# 	} else {
# 	    set req.http.X-Forwarded-For = client.ip;
# 	}
#     }
#     if (req.request != "GET" &&
#       req.request != "HEAD" &&
#       req.request != "PUT" &&
#       req.request != "POST" &&
#       req.request != "TRACE" &&
#       req.request != "OPTIONS" &&
#       req.request != "DELETE") {
#         /* Non-RFC2616 or CONNECT which is weird. */
#         return (pipe);
#     }
#     if (req.request != "GET" && req.request != "HEAD") {
#         /* We only deal with GET and HEAD by default */
#         return (pass);
#     }
#     if (req.http.Authorization || req.http.Cookie) {
#         /* Not cacheable by default */
#         return (pass);
#     }
#     return (lookup);
# }
#
# sub vcl_pipe {
#     # Note that only the first request to the backend will have
#     # X-Forwarded-For set.  If you use X-Forwarded-For and want to
#     # have it set for all requests, make sure to have:
#     # set bereq.http.connection = "close";
#     # here.  It is not set by default as it might break some broken web
#     # applications, like IIS with NTLM authentication.
#     return (pipe);
# }
#
# sub vcl_pass {
#     return (pass);
# }
#
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (hash);
# }
#
# sub vcl_hit {
#     return (deliver);
# }
#
# sub vcl_miss {
#     return (fetch);
# }
#
# sub vcl_fetch {
#     if (beresp.ttl <= 0s ||
#         beresp.http.Set-Cookie ||
#         beresp.http.Vary == "*") {
# 		/*
# 		 * Mark as "Hit-For-Pass" for the next 2 minutes
# 		 */
# 		set beresp.ttl = 120 s;
# 		return (hit_for_pass);
#     }
#     return (deliver);
# }
#
# sub vcl_deliver {
#     return (deliver);
# }
#
# sub vcl_error {
#     set obj.http.Content-Type = "text/html; charset=utf-8";
#     set obj.http.Retry-After = "5";
#     synthetic {"
# <?xml version="1.0" encoding="utf-8"?>
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
#  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
#
#
#     <title>"} + obj.status + " " + obj.response + {"</title>
#
#
#
Error "} + obj.status + " " + obj.response + {"

#
"} + obj.response + {"

#
Guru Meditation:

#
XID: "} + req.xid + {"

#

#
Varnish cache server

#
#
# "};
#     return (deliver);
# }
#
# sub vcl_init {
# 	return (ok);
# }
#
# sub vcl_fini {
# 	return (ok);
# }


Only bypass for logged in users, not logged out

# Pass all local or login/admin requests straight through
if (req.http.Host ~ "^local\." || (req.url ~ "wp-(login|admin)")) {
    return (pass);
}

if (req.http.Cookie ~ "^wordpress_logged_in_") {
  return (pass);
}

# Drop any cookies sent to Wordpress.
if (!(req.url ~ "wp-(login|admin)")) {
    unset req.http.Cookie;
}

# Anything else left?
if (!req.http.Cookie) {
    unset req.http.Cookie;
}

# Try a cache-lookup
return (lookup);

# Pass all local or login/admin requests straight through
if (req.http.Host ~ "^local\." || (req.url ~ "wp-(login|admin)")) {
    return (pass);
}

if (req.http.Cookie ~ "^wp-" || req.http.Cookie ~ "^wordpress_") {
  return (pass);
}

# Drop any cookies sent to Wordpress.
if (!(req.url ~ "wp-(login|admin)")) {
    unset req.http.Cookie;
}

# Anything else left?
if (!req.http.Cookie) {
    unset req.http.Cookie;
}

# Try a cache-lookup
return (lookup);


Add comments

Add comments

sub vcl_recv {
  if (req.restarts < 1) {
    # Sanitise header
    unset req.http.X-eLife-Restart;
  }

  #FASTLY recv

  if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
    return(pass);
  }

  return(lookup);
}

sub vcl_fetch {
  #FASTLY fetch

  if (beresp.status >= 500 && beresp.status < 600) {
    if (stale.exists) {
      return(deliver_stale);
    }

    if (req.restarts < 1 && (req.request == "GET" || req.request == "HEAD")) {
      set req.http.X-eLife-Restart = "fetch," beresp.status;
      unset req.http.Cookie; # Temporarily log out the user

      restart;
    }

    if (!beresp.http.Content-Length || beresp.http.Content-Length == "0") {
      error beresp.status;
    }
  }

  if (req.restarts > 0) {
    set beresp.http.Fastly-Restarts = req.restarts;
  }

  if (beresp.http.Set-Cookie) {
    set req.http.Fastly-Cachetype = "SETCOOKIE";
    return(pass);
  }

  if (beresp.http.Cache-Control ~ "private") {
    set req.http.Fastly-Cachetype = "PRIVATE";
    return(pass);
  }

  if (beresp.status == 500 || beresp.status == 503) {
    set req.http.Fastly-Cachetype = "ERROR";
    set beresp.ttl = 1s;
    set beresp.grace = 5s;
    return(deliver);
  }

  if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
    # keep the ttl here
  } else {
    # apply the default ttl
    set beresp.ttl = 3600s;
  }

  return(deliver);
}

sub vcl_hit {
  #FASTLY hit

  if (!obj.cacheable) {
    return(pass);
  }
  return(deliver);
}

sub vcl_miss {
  #FASTLY miss
  return(fetch);
}

sub vcl_deliver {
  if (resp.status >= 500 && resp.status < 600 && stale.exists) {
    set req.http.X-eLife-Restart = "deliver," resp.status;

    restart;
  }

  if (req.http.Fastly-Debug && req.http.X-eLife-Restart) {
    set resp.http.X-eLife-Restart = req.http.X-eLife-Restart;
  }

  #FASTLY deliver
  return(deliver);
}

sub vcl_error {
  if (obj.status >= 500 && obj.status < 600 && stale.exists) {
    return(deliver_stale);
  }

  #FASTLY error
}

sub vcl_pass {
  #FASTLY pass
}

sub vcl_log {
  #FASTLY log
}

sub vcl_recv {
  if (req.restarts < 1) {
    unset req.http.X-eLife-Restart;
  }

  #FASTLY recv

  if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
    return(pass);
  }

  return(lookup);
}

sub vcl_fetch {
  #FASTLY fetch

  if (beresp.status >= 500 && beresp.status < 600) {
    if (stale.exists) {
      return(deliver_stale);
    }

    if (req.restarts < 1 && (req.request == "GET" || req.request == "HEAD")) {
      set req.http.X-eLife-Restart = "fetch," beresp.status;
      unset req.http.Cookie;

      restart;
    }

    if (!beresp.http.Content-Length || beresp.http.Content-Length == "0") {
      error beresp.status;
    }
  }

  if (req.restarts > 0) {
    set beresp.http.Fastly-Restarts = req.restarts;
  }

  if (beresp.http.Set-Cookie) {
    set req.http.Fastly-Cachetype = "SETCOOKIE";
    return(pass);
  }

  if (beresp.http.Cache-Control ~ "private") {
    set req.http.Fastly-Cachetype = "PRIVATE";
    return(pass);
  }

  if (beresp.status == 500 || beresp.status == 503) {
    set req.http.Fastly-Cachetype = "ERROR";
    set beresp.ttl = 1s;
    set beresp.grace = 5s;
    return(deliver);
  }

  if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
    # keep the ttl here
  } else {
    # apply the default ttl
    set beresp.ttl = 3600s;
  }

  return(deliver);
}

sub vcl_hit {
  #FASTLY hit

  if (!obj.cacheable) {
    return(pass);
  }
  return(deliver);
}

sub vcl_miss {
  #FASTLY miss
  return(fetch);
}

sub vcl_deliver {
  if (resp.status >= 500 && resp.status < 600 && stale.exists) {
    set req.http.X-eLife-Restart = "deliver," resp.status;

    restart;
  }

  if (req.http.Fastly-Debug && req.http.X-eLife-Restart) {
    set resp.http.X-eLife-Restart = req.http.X-eLife-Restart;
  }

  #FASTLY deliver
  return(deliver);
}

sub vcl_error {
  if (obj.status >= 500 && obj.status < 600 && stale.exists) {
    return(deliver_stale);
  }

  #FASTLY error
}

sub vcl_pass {
  #FASTLY pass
}

sub vcl_log {
  #FASTLY log
}