fix some syntax errors

fix some syntax errors

/* Varnish 3 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.
# Loosely based on http://www.lullabot.com/sites/default/files/default_varnish3.vcl_.txt

/* Backend probes / healthchecks */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#backend-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/3.0/reference/vcl.html#backend-declarations
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;
}

/* Directors. */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#directors
# Empty in simple configs

/* Access Control Lists */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#acls
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 routines */
# 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.*$" ) {
#     error 751 "http://" + regsub(req.http.host, "^www\.", "") + req.url;
#   }
# }
# sub perm_redirections_error {
#   if (obj.status == 751) {
#     /* Get new URL from the response */
#     set obj.http.Location = obj.response;
#     /* Set HTTP 301 for permanent redirect */
#     set obj.status = 301;
#     return(deliver);
#   }
# }

/* VCL logigc overrides */
# 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
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#subroutines

# 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.
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.
  # error 200 "Ok";
  # Finally we can perform basic HTTP authentification here by example.
  # See http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* 1st: Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    return (lookup);
  }
  # Ban logic. See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#bans
  if (req.request == "BAN") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    ban("req.http.host == " + req.http.host +
      "&& req.url == " + req.url);
    error 200 "Ban added";
  }
  # 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.request == "OPTIONS" || req.request == "GET" )
    ) {
    error 200 "Ok";
  }

  /* 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: Set custom headers for backend like X-Forwarded-For (copied from built-in logic) */
  if ( req.restarts == 0 ) {
    /* See also vcl_pipe section */
    if ( ! client.ip ~ own_proxys ) {
      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;
      }
    }
  }

  /* 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.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) {
    /* 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.
  #   error 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: Enable grace mode */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  if (! req.backend.healthy) {
    /* Use a longer grace period if all backends are down */
    set req.grace = 1h;
    /* Use anonymous, cached pages if all backends are down. */
    unset req.http.Cookie;
    # TO-DO: Add sick marker
  } else {
    /* Allow the backend to serve up stale content if it is responding slowly. */
    set req.grace = 30s;
  }

  /* 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/3.0/phk/gzip.html#what-does-http-gzip-support-do
  # See https://www.varnish-cache.org/docs/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.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 ~ "(?i)\.(7z|avi|bz2|flv|gif|gz|jpe?g|mpe?g|mk[av]|mov|mp[34]|og[gm]|pdf|png|rar|swf|tar|tbz|tgz|woff2?|zip|xz)(\?.*)?$"
    ) {
      /* Already compressed formats, no sense trying to compress again */
      remove 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)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(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 a lookup.
  return (lookup);
}

# 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.
sub vcl_pipe {
  /* Prevent connection re-using for piped requests */
  # Note that only the first request to the backend will have X-Forwarded-For set.
  # As we use X-Forwarded-For and want to have it set for all requests,
  # we have to make sure connection won't be reused after the request.
  # It is not set by default as it might break some broken web applications, like IIS with NTLM authentication.
  # See https://www.varnish-cache.org/trac/wiki/VCLExamplePipe
  # TO-DO: make sure this is compatible with websockets piping,
  # reference https://www.varnish-cache.org/docs/3.0/tutorial/websockets.html
  set bereq.http.connection = "close";

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  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.
# sub vcl_pass {
#     return (pass);
# }

# 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.
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)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(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 (hash);
# }

# vcl_hit: Called after a cache lookup if the requested document was found in the cache.
sub vcl_hit {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

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

# 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.
sub vcl_miss {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

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

# vcl_fetch: Called after a document has been successfully retrieved from the backend.
sub vcl_fetch {
  /* Caching exceptions */
  # Varnish will cache objects with response codes: 200, 203, 300, 301, 302, 307, 404 & 410.
  # See 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 &&
      /* TO-DO: verify that this work better than 'req.url ~ "imagecache"' */
      beresp.http.Location == req.url &&
      beresp.ttl > 5s) {
    set beresp.ttl = 5s;
    set beresp.http.cache-control = "max-age=5";
  }

  /* Enable grace mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  set beresp.grace = 1h;

  /* Enable saint mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#saint-mode
  if (beresp.status == 500) {
    set beresp.saintmode = 20s;
    # TO-DO: consider not restarting POST requests as seen on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
    return(restart);
  }

  /* Strip cookies from the following static file types for all users. Related with our 12th stage on vcl_recv */
  if ( req.url ~ "(?i)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(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/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.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;
    if ( beresp.http.Vary ) {
      if ( ! beresp.http.Vary ~ "Accept-Encoding" ) {
        set beresp.http.Vary = beresp.http.Vary + ",Accept-Encoding";
      }
    } else {
      set beresp.http.Vary = "Accept-Encoding";
    }
  }

  /* 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 (req.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;

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# 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);
# }

# vcl_deliver: Called before an object is delivered to the client
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.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
    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;
  }
  # TO-DO: 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_error: Called when we hit an error, either explicitly or implicitly due to backend or internal errors.
sub vcl_error {
  /* Avoid DOS vulnerability CVE-2013-4484 */
  # See https://www.varnish-cache.org/lists/pipermail/varnish-announce/2013-October/000686.html
  if (obj.status == 400 || obj.status == 413) {
    return(deliver);
  }

  /* Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_error;

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

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

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

  /* We're using error 200 for monitoring puposes */
  # Consider adding some analytics stuff to trace accesses
  if (obj.status == 200) {
    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">
      <html>
        <head>
          <title>"} + obj.status + " " + obj.response + {"</title>
      </head>
      <body><h1>"} + obj.status + ": " + obj.response + {"</h1></body>
    "};
    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 3 (not so pretty)
  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">
<html>
  <head>
    <title>"} + obj.status + " " + obj.response + {"</title>
  </head>
  <body>
    <h1>Error "} + obj.status + " " + obj.response + {"</h1>
    <p>"} + obj.response + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <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);
}

# vcl_init: Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
# 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.
# sub vcl_fini {
#       return (ok);
# }

/* Varnish 3 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.
# Loosely based on http://www.lullabot.com/sites/default/files/default_varnish3.vcl_.txt

/* Backend probes / healthchecks */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#backend-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/3.0/reference/vcl.html#backend-declarations
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;
}

/* Directors. */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#directors
# Empty in simple configs

/* Access Control Lists */
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#acls
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 routines */
# 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.*$" ) {
#     error 751 "http://" + regsub(req.http.host, "^www\.", "") + req.url;
#   }
# }
# sub perm_redirections_error {
#   if (obj.status == 751) {
#     /* Get new URL from the response */
#     set obj.http.Location = obj.response;
#     /* Set HTTP 301 for permanent redirect */
#     set obj.status = 301;
#     return(deliver);
#   }
# }

/* VCL logigc overrides */
# 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
# See https://www.varnish-cache.org/docs/3.0/reference/vcl.html#subroutines

# 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.
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.
  # error 200 "Ok";
  # Finally we can perform basic HTTP authentification here by example.
  # See http://blog.tenya.me/blog/2011/12/14/varnish-http-authentication/

  /* 1st: Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    return (lookup);
  }
  # Ban logic. See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#bans
  if (req.request == "BAN") {
    if (!client.ip ~ purge_ban) {
      error 405 "Not allowed.";
    }
    ban("req.http.host == " + req.http.host +
      "&& req.url == " + req.url);
    error 200 "Ban added";
  }
  # 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.request == "OPTIONS" || req.request == "GET" )
    ) {
    error 200 "Ok";
  }

  /* 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: Set custom headers for backend like X-Forwarded-For (copied from built-in logic) */
  if ( req.restarts == 0 ) {
    /* See also vcl_pipe section */
    if ( ! client.ip ~ own_proxys ) {
      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;
      }
    }
  }

  /* 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.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) {
    /* 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.
  #   error 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: Enable grace mode */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  if (! req.backend.healthy) {
    /* Use a longer grace period if all backends are down */
    set req.grace = 1h;
    /* Use anonymous, cached pages if all backends are down. */
    unset req.http.Cookie;
    # TO-DO: Add sick marker
  } else {
    /* Allow the backend to serve up stale content if it is responding slowly. */
    set req.grace = 30s;
  }

  /* 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/3.0/phk/gzip.html#what-does-http-gzip-support-do
  # See https://www.varnish-cache.org/docs/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.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 ~ "(?i)\.(7z|avi|bz2|flv|gif|gz|jpe?g|mpe?g|mk[av]|mov|mp[34]|og[gm]|pdf|png|rar|swf|tar|tbz|tgz|woff2?|zip|xz)(\?.*)?$"
      /* Already compressed formats, no sense trying to compress again */
      remove 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)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(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 a lookup.
  return (lookup);
}

# 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.
sub vcl_pipe {
  /* Prevent connection re-using for piped requests */
  # Note that only the first request to the backend will have X-Forwarded-For set.
  # As we use X-Forwarded-For and want to have it set for all requests,
  # we have to make sure connection won't be reused after the request.
  # It is not set by default as it might break some broken web applications, like IIS with NTLM authentication.
  # See https://www.varnish-cache.org/trac/wiki/VCLExamplePipe
  # TO-DO: make sure this is compatible with websockets piping,
  # reference https://www.varnish-cache.org/docs/3.0/tutorial/websockets.html
  set bereq.http.connection = "close";

  /* Bypass built-in logic */
  # We make sure no built-in logic is processed after ours returning at this point.
  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.
# sub vcl_pass {
#     return (pass);
# }

# 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.
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)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(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 (hash);
# }

# vcl_hit: Called after a cache lookup if the requested document was found in the cache.
sub vcl_hit {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

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

# 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.
sub vcl_miss {
  /* Check for Varnish special requests */
  # Purge logic.
  # See https://www.varnish-cache.org/docs/3.0/tutorial/purging.html#http-purges
  # See https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }

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

# vcl_fetch: Called after a document has been successfully retrieved from the backend.
sub vcl_fetch {
  /* Caching exceptions */
  # Varnish will cache objects with response codes: 200, 203, 300, 301, 302, 307, 404 & 410.
  # See 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 &&
      /* TO-DO: verify that this work better than 'req.url ~ "imagecache"' */
      beresp.http.Location == req.url &&
      beresp.ttl > 5s) {
    set beresp.ttl = 5s;
    set beresp.http.cache-control = "max-age=5";
  }

  /* Enable grace mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode
  set beresp.grace = 1h;

  /* Enable saint mode. Related with our 9th stage on vcl_recv */
  # See https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#saint-mode
  if (beresp.status == 500) {
    set beresp.saintmode = 20s;
    # TO-DO: consider not restarting POST requests as seen on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
    return(restart);
  }

  /* Strip cookies from the following static file types for all users. Related with our 12th stage on vcl_recv */
  if ( req.url ~ "(?i)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(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/3.0/tutorial/compression.html
  # See https://www.varnish-cache.org/docs/3.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;
    if ( beresp.http.Vary ) {
      if ( ! beresp.http.Vary ~ "Accept-Encoding" ) {
        set beresp.http.Vary = beresp.http.Vary + ",Accept-Encoding";
      }
    } else {
      set beresp.http.Vary = "Accept-Encoding";
    }
  }

  /* 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 (req.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;

  /* Continue with built-in logic */
  # We want built-in logic to be processed after ours so we don't call return.
}
# 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);
# }

# vcl_deliver: Called before an object is delivered to the client
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.
  # https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
    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;
  }
  # TO-DO: 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_error: Called when we hit an error, either explicitly or implicitly due to backend or internal errors.
sub vcl_error {
  /* Avoid DOS vulnerability CVE-2013-4484 */
  # See https://www.varnish-cache.org/lists/pipermail/varnish-announce/2013-October/000686.html
  if (obj.status == 400 || obj.status == 413) {
    return(deliver);
  }

  /* Do some Varnish black magic such as custom client redirections */
  # Empty in simple configs.
  # call perm_redirections_error;

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

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

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

  /* We're using error 200 for monitoring puposes */
  # Consider adding some analytics stuff to trace accesses
  if (obj.status == 200) {
    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">
      <html>
        <head>
          <title>"} + obj.status + " " + obj.response + {"</title>
      </head>
      <body><h1>"} + obj.status + ": " + obj.response + {"</h1></body>
    "};
    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 3 (not so pretty)
  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">
<html>
  <head>
    <title>"} + obj.status + " " + obj.response + {"</title>
  </head>
  <body>
    <h1>Error "} + obj.status + " " + obj.response + {"</h1>
    <p>"} + obj.response + {"</p>
    <h3>Guru Meditation:</h3>
    <p>XID: "} + req.xid + {"</p>
    <hr>
    <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);
}

# vcl_init: Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
# 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.
# sub vcl_fini {
#       return (ok);
# }


Redirect to https if the host is just polyfill.io (#730)

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 && (req.http.Host == "cdn.polyfill.io" || req.http.Host == "polyfill.io")) {
		error 751 "Force TLS";
	}

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

	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) {
		set req.http.Fastly-force-Shield = "1";
		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";
	}
	return(deliver);
}

sub vcl_error {

	# Redirect to SSL
	if (obj.status == 751) {
		set obj.status = 301;
		set obj.response = "Moved Permanently";
		set obj.http.Location = "https://" req.http.host req.url;
		synthetic {""};
		return (deliver);
	}
}

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 && req.http.Host == "cdn.polyfill.io") {
		error 751 "Force TLS";
	}

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

	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) {
		set req.http.Fastly-force-Shield = "1";
		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";
	}
	return(deliver);
}

sub vcl_error {

	# Redirect to SSL
	if (obj.status == 751) {
		set obj.status = 301;
		set obj.response = "Moved Permanently";
		set obj.http.Location = "https://" req.http.host req.url;
		synthetic {""};
		return (deliver);
	}
}


Letting GQL cacheing work on HEAD requests as well

    # When using Magento tester to test whether your site is configured properly
    # this uses a bypass secret. By default we will use service ID as the bypass secret
    # however user can override this by defining a bypass_secret key in the
    # magentomodule_config edge dictionary
    if ( req.http.bypass-secret ) {
        declare local var.bypass-secret STRING;
        set var.bypass-secret = table.lookup(magentomodule_config, "bypass_secret", "NONE");
        if ( var.bypass-secret == req.http.bypass-secret ) {
            set req.http.x-pass = "1";
            set var.fastly_req_do_shield = false;
            set req.hash_always_miss = true;
        } else if ( var.bypass-secret == "NONE" && req.http.bypass-secret == req.service_id ) {
            set req.http.x-pass = "1";
            set var.fastly_req_do_shield = false;
            set req.hash_always_miss = true;
        } else {
            error 403 "Bypass Secret incorrect";
        }

        if (req.url == "/fastly-io-tester") {
            # IO won't work for PASS requests
            unset req.http.x-pass;
            set req.hash_always_miss = true;
            set req.http.X-Fastly-Imageopto-Api = "fastly";
        }
    }

    # VCL required to support maintenance mode. Don't maintenance mode admin pages and supporting assets
    if (table.lookup(magentomodule_config, "allow_super_users_during_maint", "0") == "1" &&
        !req.http.Fastly-Client-Ip ~ maint_allowlist &&
        !req.url ~ "^/(index\.php/)?####ADMIN_PATH####/" &&
        !req.url ~ "^/pub/static/") {

        # If we end up here after a restart and there is a ResponseObject it means we got here after error
        # page VCL restart. We shouldn't touch it. Otherwise return a plain 503 error page
        if ( req.restarts > 0 && req.http.ResponseObject ) {
            set req.http.ResponseObject = "970";
        } else {
            error 503 "Maintenance mode";
        }
    }

    # 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;
    }

    unset req.http.x-long-cache;

    # We want to force long cache times on any of the versioned assets
    if (req.url.path ~ "^/static/version\d*/") {
       set req.http.x-long-cache = "1";
    }

    # User's Cookie may contain some Magento Vary items we should vary on
    if (req.http.cookie:X-Magento-Vary) {
        set req.http.X-Magento-Vary = req.http.cookie:X-Magento-Vary;
    } else {
        unset req.http.X-Magento-Vary;
    }

    ############################################################################################################
    # Following code block controls purge by URL. By default we want to protect all URL purges. In general this
    # is addressed by adding Fastly-Purge-Requires-Auth request header in vcl_recv however this runs the risk of
    # exposing API tokens if user attempts to purge non-https URLs. For this reason inside the Magento module
    # we use X-Purge-Token. Unfortunately this breaks purge from the Fastly UI. Therefore in the next code block
    # we check for presence of X-Purge-Token. If it's not present we force the Fastly-Purge-Requires-Auth
    if (req.request == "FASTLYPURGE") {
        # extract token signature and expiration
        if (req.http.X-Purge-Token && req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) {

            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;
            }
        } else {
            set req.http.Fastly-Purge-Requires-Auth = "1";
        }
    }

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

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

    # Make sure we lookup end user geo not shielding. More at https://docs.fastly.com/vcl/geolocation/#using-geographic-variables-with-shielding
    set client.geo.ip_override = req.http.Fastly-Client-IP;

    if ((req.request == "GET" || req.request == "HEAD") && req.url.path ~ "/graphql" && req.url.qs ~ "query=") {
        set req.http.graphql = "1";
    } else {
        unset req.http.graphql;
    }

    # geoip lookup
    if (req.url.path ~ "fastlyCdn/geoip/getaction/") {
        # check if GeoIP has been already processed by client. this normally happens before essential cookies are set.
        if (req.http.cookie:X-Magento-Vary || req.http.cookie:form_key) {
            error 980 "GeoIP already processed";
        } else {
            # append parameter with country code only if it doesn't exist already
            if ( req.url.qs !~ "country_code=" ) {
                set req.url = querystring.set(req.url, "country_code", if ( req.http.geo_override, req.http.geo_override, client.geo.country_code));
            }
        }
    } else if ( req.url.path !~ "/graphql" ) {
        # Per suggestions in https://github.com/sdinteractive/SomethingDigital_PageCacheParams
        # we'll strip out query parameters used in Google AdWords, Mailchimp tracking by default
        # and allow custom parameters to be set. List of parameters is configurable in admin
        set req.http.Magento-Original-URL = req.url;
        # Change the list of ignored parameters by configuring them in the Advanced section
        set req.url = querystring.regfilter(req.url, "^(####QUERY_PARAMETERS####)$");
    }

    # Don't allow clients to force a pass
    if (req.restarts == 0) {
        unset req.http.x-pass;
        unset req.http.Rate-Limit;
        unset req.http.magento-admin-path;
    }

    # Pass on checkout URLs. Because it's a snippet we want to execute this after backend selection so we handle it
    # in the request condition
    if (!req.http.x-long-cache && req.url ~ "/(checkout|customer/section/load)") {
        set req.http.x-pass = "1";
    # Pass all admin actions
    # ####ADMIN_PATH#### is replaced with value of frontName from app/etc/env.php
    } else if ( req.url ~ "^/(index\.php/)?####ADMIN_PATH####/" ) {
        set req.http.x-pass = "1";
        set req.http.magento-admin-path = "1";
    } else {
        # Sort the query arguments to increase cache hit ratio with query arguments that
        # may be out od order. In case you want to restore the unsorted URL add a snippet
        # after this one that sets req.url to req.http.Magento-Original-URL
        if ( !req.http.x-pass ) {
            set req.url = boltsort.sort(req.url);
        }
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.http.x-long-cache || req.url ~ "^/(pub/)?(media|static)/.*") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # GraphQL special headers handling because this area doesn't rely on X-Magento-Vary cookie
    if (req.http.graphql && !req.http.X-Magento-Cache-Id && req.http.Authorization ~ "^Bearer" ) {
        unset req.http.graphql;
        set req.http.x-pass = "1";
    }

    # When using Magento tester to test whether your site is configured properly
    # this uses a bypass secret. By default we will use service ID as the bypass secret
    # however user can override this by defining a bypass_secret key in the
    # magentomodule_config edge dictionary
    if ( req.http.bypass-secret ) {
        declare local var.bypass-secret STRING;
        set var.bypass-secret = table.lookup(magentomodule_config, "bypass_secret", "NONE");
        if ( var.bypass-secret == req.http.bypass-secret ) {
            set req.http.x-pass = "1";
            set var.fastly_req_do_shield = false;
            set req.hash_always_miss = true;
        } else if ( var.bypass-secret == "NONE" && req.http.bypass-secret == req.service_id ) {
            set req.http.x-pass = "1";
            set var.fastly_req_do_shield = false;
            set req.hash_always_miss = true;
        } else {
            error 403 "Bypass Secret incorrect";
        }

        if (req.url == "/fastly-io-tester") {
            # IO won't work for PASS requests
            unset req.http.x-pass;
            set req.hash_always_miss = true;
            set req.http.X-Fastly-Imageopto-Api = "fastly";
        }
    }

    # VCL required to support maintenance mode. Don't maintenance mode admin pages and supporting assets
    if (table.lookup(magentomodule_config, "allow_super_users_during_maint", "0") == "1" &&
        !req.http.Fastly-Client-Ip ~ maint_allowlist &&
        !req.url ~ "^/(index\.php/)?####ADMIN_PATH####/" &&
        !req.url ~ "^/pub/static/") {

        # If we end up here after a restart and there is a ResponseObject it means we got here after error
        # page VCL restart. We shouldn't touch it. Otherwise return a plain 503 error page
        if ( req.restarts > 0 && req.http.ResponseObject ) {
            set req.http.ResponseObject = "970";
        } else {
            error 503 "Maintenance mode";
        }
    }

    # 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;
    }

    unset req.http.x-long-cache;

    # We want to force long cache times on any of the versioned assets
    if (req.url.path ~ "^/static/version\d*/") {
       set req.http.x-long-cache = "1";
    }

    # User's Cookie may contain some Magento Vary items we should vary on
    if (req.http.cookie:X-Magento-Vary) {
        set req.http.X-Magento-Vary = req.http.cookie:X-Magento-Vary;
    } else {
        unset req.http.X-Magento-Vary;
    }

    ############################################################################################################
    # Following code block controls purge by URL. By default we want to protect all URL purges. In general this
    # is addressed by adding Fastly-Purge-Requires-Auth request header in vcl_recv however this runs the risk of
    # exposing API tokens if user attempts to purge non-https URLs. For this reason inside the Magento module
    # we use X-Purge-Token. Unfortunately this breaks purge from the Fastly UI. Therefore in the next code block
    # we check for presence of X-Purge-Token. If it's not present we force the Fastly-Purge-Requires-Auth
    if (req.request == "FASTLYPURGE") {
        # extract token signature and expiration
        if (req.http.X-Purge-Token && req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) {

            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;
            }
        } else {
            set req.http.Fastly-Purge-Requires-Auth = "1";
        }
    }

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

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

    # Make sure we lookup end user geo not shielding. More at https://docs.fastly.com/vcl/geolocation/#using-geographic-variables-with-shielding
    set client.geo.ip_override = req.http.Fastly-Client-IP;

    if (req.request == "GET" && req.url.path ~ "/graphql" && req.url.qs ~ "query=") {
        set req.http.graphql = "1";
    } else {
        unset req.http.graphql;
    }

    # geoip lookup
    if (req.url.path ~ "fastlyCdn/geoip/getaction/") {
        # check if GeoIP has been already processed by client. this normally happens before essential cookies are set.
        if (req.http.cookie:X-Magento-Vary || req.http.cookie:form_key) {
            error 980 "GeoIP already processed";
        } else {
            # append parameter with country code only if it doesn't exist already
            if ( req.url.qs !~ "country_code=" ) {
                set req.url = querystring.set(req.url, "country_code", if ( req.http.geo_override, req.http.geo_override, client.geo.country_code));
            }
        }
    } else if ( req.url.path !~ "/graphql" ) {
        # Per suggestions in https://github.com/sdinteractive/SomethingDigital_PageCacheParams
        # we'll strip out query parameters used in Google AdWords, Mailchimp tracking by default
        # and allow custom parameters to be set. List of parameters is configurable in admin
        set req.http.Magento-Original-URL = req.url;
        # Change the list of ignored parameters by configuring them in the Advanced section
        set req.url = querystring.regfilter(req.url, "^(####QUERY_PARAMETERS####)$");
    }

    # Don't allow clients to force a pass
    if (req.restarts == 0) {
        unset req.http.x-pass;
        unset req.http.Rate-Limit;
        unset req.http.magento-admin-path;
    }

    # Pass on checkout URLs. Because it's a snippet we want to execute this after backend selection so we handle it
    # in the request condition
    if (!req.http.x-long-cache && req.url ~ "/(checkout|customer/section/load)") {
        set req.http.x-pass = "1";
    # Pass all admin actions
    # ####ADMIN_PATH#### is replaced with value of frontName from app/etc/env.php
    } else if ( req.url ~ "^/(index\.php/)?####ADMIN_PATH####/" ) {
        set req.http.x-pass = "1";
        set req.http.magento-admin-path = "1";
    } else {
        # Sort the query arguments to increase cache hit ratio with query arguments that
        # may be out od order. In case you want to restore the unsorted URL add a snippet
        # after this one that sets req.url to req.http.Magento-Original-URL
        if ( !req.http.x-pass ) {
            set req.url = boltsort.sort(req.url);
        }
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.http.x-long-cache || req.url ~ "^/(pub/)?(media|static)/.*") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # GraphQL special headers handling because this area doesn't rely on X-Magento-Vary cookie
    if (req.http.graphql && !req.http.X-Magento-Cache-Id && req.http.Authorization ~ "^Bearer" ) {
        unset req.http.graphql;
        set req.http.x-pass = "1";
    }


Adding another acl for 192.*.

Adding another acl for 192.*.

import std;
backend poky {
  .host = "127.0.0.1";
  .port = "8081";               # make sure this syncs up with the deploy config
  .connect_timeout = 1s;
  .first_byte_timeout = 5s;
  .between_bytes_timeout = 2s;
  .probe = {
      .url = "/status";
      .interval = 5s;
      .timeout = 1s;
      .window = 5;
      .threshold = 3;
  }
}

acl purgers {
    "127.0.0.1";
    "10.0.0.0"/8;
    "192.0.0.0"/8;
}

sub vcl_recv {
    # If-Match is stripped before being sent to the backend
    set req.http.X-If-Match = req.http.If-Match;
    set req.backend = poky;
    set req.grace = 5m;

    if (req.request == "PURGE") {
        if (!client.ip ~ purgers) {
            error 405 "Method not allowed";
        }

        return (lookup);
    }

    if (req.url ~ "^/status$") {
        return (pass);
    }
}

sub vcl_hash {
    # we only ever need to hash on the req.url since there is only one
    # host/server.
    hash_data(req.url);
    return (hash);
}

sub vcl_fetch {
    set beresp.http.x-url = req.url;
    set beresp.http.x-host = req.http.host;
    set beresp.grace = 5m;

    if (beresp.status == 200) {
        set beresp.ttl = 4h;
    }

    if (beresp.status == 404) {
        # we want to bypass the default hit_for_pass object so we can get HITs on this immediately
        # if it's updated. otherwise, we will encounter misses for 120s
        set beresp.ttl = 0s;
        return (deliver);
    }

    if (beresp.status >= 500) {
        set beresp.ttl = 0s;
    }
}

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

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

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

sub vcl_pass {
        if (req.request == "PURGE") {
                error 503 "Shouldn't get to (pass) on PURGE.";
        }
}

import std;
backend poky {
  .host = "127.0.0.1";
  .port = "8081";               # make sure this syncs up with the deploy config
  .connect_timeout = 1s;
  .first_byte_timeout = 5s;
  .between_bytes_timeout = 2s;
  .probe = {
      .url = "/status";
      .interval = 5s;
      .timeout = 1s;
      .window = 5;
      .threshold = 3;
  }
}

acl purgers {
    "127.0.0.1";
    "10.0.0.0"/8;
}

sub vcl_recv {
    # If-Match is stripped before being sent to the backend
    set req.http.X-If-Match = req.http.If-Match;
    set req.backend = poky;
    set req.grace = 5m;

    if (req.request == "PURGE") {
        if (!client.ip ~ purgers) {
            error 405 "Method not allowed";
        }

        return (lookup);
    }

    if (req.url ~ "^/status$") {
        return (pass);
    }
}

sub vcl_hash {
    # we only ever need to hash on the req.url since there is only one
    # host/server.
    hash_data(req.url);
    return (hash);
}

sub vcl_fetch {
    set beresp.http.x-url = req.url;
    set beresp.http.x-host = req.http.host;
    set beresp.grace = 5m;

    if (beresp.status == 200) {
        set beresp.ttl = 4h;
    }

    if (beresp.status == 404) {
        # we want to bypass the default hit_for_pass object so we can get HITs on this immediately
        # if it's updated. otherwise, we will encounter misses for 120s
        set beresp.ttl = 0s;
        return (deliver);
    }

    if (beresp.status >= 500) {
        set beresp.ttl = 0s;
    }
}

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

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

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

sub vcl_pass {
        if (req.request == "PURGE") {
                error 503 "Shouldn't get to (pass) on PURGE.";
        }
}