Kristian Lyngstøl's Blog

Stripping cookies with VCL

Posted on 2010-08-13

The easiest way to get Varnish to help you out of the box, is to strip cookies you don't want. Other than that, the default settings are pretty good.

So to ease that whole mess, I wrote a bash script for the occasion, maintained as of now at http://varnish-cache.org/browser/trunk/varnish-tools/cookie-stripper. It can create everything you need for a VCL file to just remove cookies and define a web server. A copy of the current version is here:

#!/bin/sh
# Author: Kristian Lyngstol
# Date: August 2010
# More info: http://kly.no/
# License: Consider it public domain.
#

usage() {
echo
echo "Varnish Cookie-strip VCL generator"
echo "Copyright (C) 2010 Kristian Lyngstol "
echo
echo "$0 [-b backend:port] [-i indentation] [-c cookie] [-c cookie] ..."
echo "Generates VCL for Varnish to strip cookies."
echo " -c \tStrip cookie named \`cookie'. Can be"
echo "            \tspecified multiple times"
echo " -b \tAlso generate the backend definition to use"
echo "               \ta web server at host:port as the backend. Both"
echo "               \thost AND port, separated by colon, must be specified"
echo " -t \tUse \`indent' when indenting the code, instead of"
echo "            \t4 spaces."
echo " -i         \tCreate case-insensitive cookie matching"
echo
echo "Example: $0 -b localhost:8181 -c __utmz -c __utma > /etc/varnish/default.vcl"
echo
echo "The VCL generated is for Varnish 2.1 and beyond and with the"
echo "-b option there is no need to add or modify the final VCL to"
echo "make Varnish \"just work\""
}
ind() {
echo -n "$indent"
}

TEMP=`getopt -o hb:c:it: -n $0 -- "$@"`

if [ $? != 0 ] ; then echo "$(usage)" >&2 ; exit 1 ; fi

eval set -- "$TEMP"

icase=""
indent="    "
backend=""
cookiestring=""

while true ; do
case "$1" in
-b) backend="$2"; shift 2;;
-i) icase="(?i)"; shift 1;;
-t) indent="$2"; shift 2;;
-c) cookiestrip="$cookiestrip $2"; shift 2;;
-h) usage; exit 0 ;;
--) shift; break ;;
*) echo "Internal error! See $0 -h" ; exit 1 ;;
esac
done

host=`echo $backend | sed s/:.*//`
port=`echo $backend | sed s/.*://`

if [ ! -z "$backend" ]; then
if [ -z "$host" ] || [ -z "$port" ]; then
echo "Invalid backend \"$backend\"" 1>&2
echo "$(usage)" 1>&2
exit 1;
fi

echo "backend default {"
ind
echo ".host = \"$host\";"
ind
echo ".port = \"$port\";"
echo "}"
echo
fi

if [ -z "$cookiestrip" ] && [ -z "$backend" ]; then
echo "No -c or -b option specified." 1>&2
echo "$(usage)" 1>&2
exit 2;
fi

echo "sub vcl_recv {"
for a in $cookiestrip; do
ind
echo "# Remove cookie $a"
ind
echo -n 'set req.http.cookie = regsub(req.http.cookie,';
echo -n "\"${icase}$a=[^;]*;?( |$)\""
echo ',"");'
done

echo
ind
echo "# Remove the cookie header if it's empty after cleanup"
ind
echo 'if (req.http.cookie ~ "^ *$") {'
ind
ind
echo 'remove req.http.cookie;'
ind
echo '}'
echo '}'

Since I don't have any cookie-needing web sites or servers, I haven't tested it properly. I figure someone else will test it if it's a worthwhile script to have around.

Feedback welcome.