Skip to content

Instantly share code, notes, and snippets.

@samsoir
Created February 10, 2011 19:01
Show Gist options
  • Save samsoir/821104 to your computer and use it in GitHub Desktop.
Save samsoir/821104 to your computer and use it in GitHub Desktop.
C{
#include <limits.h>
#include <errno.h>
}C
backend default {
.host = "192.168.192.134";
.port = "80";
}
/* Called when request arrives */
sub vcl_recv
{
#call strip_ZDEDebugger_cookies;
// Clear out cache pass header if it's set
unset req.http.X-Cache-Pass;
// clean out requests sent via curls -X mode and LWP
if (req.url ~ "^http://") {
set req.url = regsub(req.url, "http://[^/]*", "");
}
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);
}
/* Actively purge cache on updates */
if (req.request == "PUT" || req.request == "POST" || req.request == "DELETE") {
call purge_updated_entries;
}
/* We can pipe form posts, no need to interfere */
if (req.request == "POST" &&
(req.http.Transfer-Encoding == "chunked" ||
req.http.Transfer-Encoding == "multipart/form-data")) {
return (pipe);
}
/* Bypass Varnish completely when this cookie is set */
if (req.http.Cookie ~ "CW-Varnish-Bypass") {
return (pipe);
}
/* Normalise the accept encoding header */
call normalise_accept_encoding;
if (req.request == "GET" || req.request == "HEAD") {
/* stale-while-(revalidate|error) */
set req.grace = 10s;
}
}
/* Forces every pipe to be a new connection.
Otherwise pipelined requests might fall into the same pipe */
sub vcl_pipe {
set bereq.http.Connection = "Close";
}
/* Called when item is fetched, decide whether to cache or not */
sub vcl_fetch {
/* Strip cookies from static assets */
if (req.url ~ "\.(png|gif|jpg|css)$") {
unset beresp.http.set-cookie;
set beresp.ttl = 1h;
}
/* Grace for longer period */
set beresp.grace = 10s;
/* Indicate that we passed on vcl_fetch */
if (req.http.X-Cache-Pass) {
set beresp.http.X-Cache-Pass = req.http.X-Cache-Pass;
return (pass);
}
call strip_ZDEDebugger_cookies_beresp;
/* Do not cache requests that set cookies */
if (beresp.http.Set-Cookie) {
set beresp.http.X-Cache-Pass = "21";
return (pass);
}
/* Do NOT cache requests with HTTP Authentication on, unless a special cookie is set (needed to load-test Varnish) */
if (req.http.Authorization && !(req.http.Cookie ~ "CW-Varnish-No-Http-Auth")) {
set beresp.http.X-Cache-Pass = "HTTP Auth";
//set obj.http.X-Cacheable = "NO: HTTP Authentication " obj.http.X-Cacheable;
return (pass);
}
/* Cache 2xx codes only for now */
if (beresp.status < 200 || beresp.status > 299) {
set beresp.http.X-Cache-Pass = "22";
return (pass);
}
/* Handle the X-Cache-Control header */
if (beresp.http.X-Cache-Control) {
call x_cache_control;
}
/* Cache hits for pass objects. If page is not cacheable (for example Set-Cookie: XXX)
it's marked to pass during the lifetime of the object. Here we set the lifetime to very
low in order to get away from having cacheable-objects pass */
if (!beresp.cacheable) {
if (beresp.ttl > 3s) {
set beresp.ttl = 3s;
}
set beresp.http.X-Cache-Pass = "24";
return (pass);
}
/* Specific responses from backend cause us not to cache the page */
if ((beresp.http.Cache-Control && beresp.http.Cache-Control ~ "no-cache|private|no-store|max-age=0|s-maxage=0") ||
(beresp.http.Pragma && beresp.http.Pragma ~ "no-cache|private")) {
set beresp.http.X-Cache-Pass = "25";
return (pass);
} else {
/* No backend cache control. Save item for 10s and send private headers so that
upstream doesn't pick up the cached copy */
if (!beresp.http.Cache-Control) {
set beresp.ttl = 10s;
set beresp.http.Cache-Control = "private, max-age=0, no-store";
}
}
return (deliver);
}
/* Add information about whether request hit cache or not */
sub vcl_deliver {
/* PASS happens in cases where we actively pass the request */
if (resp.http.X-Cache-Pass) {
set resp.http.X-Cache-Action = "PASS (" resp.http.X-Cache-Pass ")";
unset resp.http.X-Cache-Pass;
} else {
if (obj.hits > 0) {
set resp.http.X-Cache-Action = "HIT";
set resp.http.X-Cache-Hits = obj.hits;
} else {
set resp.http.X-Cache-Action = "MISS";
}
}
/* Rename the Age header to X-Cache-Age to avoid
the age to invalidate legimite client caches */
set resp.http.X-Cache-Age = resp.http.Age;
/* remove some outgoing headers */
#unset resp.http.Age;
#unset resp.http.Via;
#unset resp.http.X-Varnish;
#unset resp.http.X-Cache-Control;
}
/* Cache configurations based on layout cookie */
sub vcl_hash {
}
/* Customize error page to show simple error message */
sub vcl_error {
/* __monitoring_check.html */
if (obj.status == 200) {
set obj.http.Content-Type = "text/html";
set obj.http.Cache-Control = "max-age=0";
synthetic obj.status " " obj.response;
return (deliver);
}
/* Possible redirects */
if (obj.status == 302 && req.url != obj.response) {
set obj.http.Location = "http://" req.http.Host obj.response;
synthetic obj.response;
return (deliver);
}
/* Only restart in case there was server error */
if (req.restarts == 0 && obj.status >= 500 && obj.status <= 599) {
return (restart);
} else {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Cache-Control = "private, max-age=0";
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>
</body>
</html>"}; // "
return (deliver);
}
}
/* ---- Function definitions ---- */
/**
* {{{ sub x_cache_control
*
* X-Cache-Control handling. This function can be called from vcl_fetch
*
* We support the following directives in X-Cache-Control header:
* - no-cache Causes varnish to pass this object (no caching made)
* - no-store Causes varnish to pass this object (no caching made)
* - max-age Allows to define custom max-age for the varnish.
*
* Note that X-Cache-Control takes precedence when it comes caching
* objects in the varnish cache
*/
sub x_cache_control
{
if (beresp.http.X-Cache-Control ~ "no-cache|no-store") {
set beresp.http.X-Cache-Pass = "23";
unset beresp.http.X-Cache-Control;
return (pass);
}
if (beresp.http.X-Cache-Control ~ "max-age=[0-9]+") {
/* Copy the ttl from the original header so that it's easier to handle in inline C */
set beresp.http.X-Cache-Control-TTL = regsub(beresp.http.X-Cache-Control, ".*max-age=([0-9]+).*", "\1");
C{
{
const char *hdr_val = 0;
char *end = 0;
/* Get the temporary header set earlier */
hdr_val = VRT_GetHdr(sp, HDR_BERESP, "\024X-Cache-Control-TTL:");
if (hdr_val != (void *)0) {
/* Get the time to live from header value */
long cache_ttl = strtol(hdr_val, &end, 0);
/* Make sure that it was a valid number and in range that we expect */
if (ERANGE != errno && end != hdr_val && cache_ttl >= 0 && cache_ttl < INT_MAX) {
/* At this point we have a suitable header */
VRT_l_beresp_ttl(sp, (cache_ttl * 1));
}
}
}
}C
/* Do not send X-Cache-Control outside */
unset beresp.http.X-Cache-Control;
unset beresp.http.X-Cache-Control-TTL;
return (deliver);
}
}
/* }}} */
/**
* {{{ sub normalise_accept_encoding
*
* Normalise the accept-encoding header so that we don't
* cache too many copies of each page.
*/
sub normalise_accept_encoding {
/* Normalise accept-encoding header */
if (req.http.Accept-Encoding) {
if (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
// unkown algorithm
unset req.http.Accept-Encoding;
}
}
}
/* }}} */
/**
* {{{ sub strip_ZDEDebugger_cookies
*
* Strip the Zend Debugger cookies
sub strip_ZDEDebugger_cookies {
set req.http.Cookie = regsuball(req.http.Cookie, "ZDEDebuggerPresent[^;]+(; )?", "");
set req.http.Cookie = regsub(req.http.Cookie, "; $", "");
if (req.http.Cookie ~ "^ *$") {
remove req.http.Cookie;
}
}
*/
/* }}} */
/**
* {{{ sub strip_ZDEDebugger_cookies_beresp
*
* Strip the Zend Debugger cookies from beresp
*/
sub strip_ZDEDebugger_cookies_beresp {
set beresp.http.Set-Cookie = regsuball(beresp.http.Set-Cookie, "ZDEDebuggerPresent[^;]+(; )?", "");
set beresp.http.Set-Cookie = regsub(beresp.http.Set-Cookie, "; $", "");
set beresp.http.Set-Cookie = regsub(beresp.http.Set-Cookie, "^path=/$", "");
if (beresp.http.Set-Cookie ~ "^ *$") {
remove beresp.http.Set-Cookie;
}
}
/* }}} */
/**
* {{{ sub purge_updated_entries
*
* Purge the cache when there's an UPDATE action
*/
sub purge_updated_entries {
// Purge the cache for the Favourites toolbar when the user adds a new favourite
call get_user_id_from_url;
if (req.http.X-Varnish-SL-Userid) {
purge("req.url ~ " req.http.X-Varnish-SL-Userid);
}
}
/* }}} */
/**
* {{{ sub get_user_id_from_url
*
* Get the User ID from the URL
* and store it into the req.http.X-Varnish-SL-Userid header
*/
sub get_user_id_from_url {
if (req.url ~ "^/customer/") {
set req.http.X-Varnish-SL-Userid = regsub(req.url, "^/customer/([^/]+)/", "\1");
}
}
/* }}} */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment