Reputation: 4461
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-54516992-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-54516992-1');
</script>
</head>
<body>
test
</body>
</html>
Backend. This is Python + Django. Please, don't be afraid. I just set a cookie here (render_to_response) and then I need a place to stop at a breakpoint (below in the code it is shown by a comment where it is).
class HomeView(TemplateView):
template_name = "home/home.html"
def render_to_response(self, context, **response_kwargs):
response = super(TemplateView, self).render_to_response(context, **response_kwargs)
response.set_cookie('sort_on', 'title')
return response
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context # Breakpoint.
varnishd For learning purposes I just clean all cookies.
$ varnishd -V
varnishd (varnish-6.0.6 revision 29a1a8243dbef3d973aec28dc90403188c1dc8e7)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2019 Varnish Software AS
VCL
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
call remove_proprietary_cookies;
if (req.http.Cookie) {
return (pass);
}
}
sub remove_proprietary_cookies{
set req.http.Cookie = regsuball(req.http.Cookie, ".*", "");
}
Then I reload the page a couple of times for the cookie to be definitely there.
In Chrome:
document.cookie
"sort_on=title; _ga=GA1.1.988164671.1586849704; _gid=GA1.1.995393496.1586849704; _gat_gtag_UA_54516992_1=1"
Picture of cookies (duplicates of the text above):
Ok. We've checked that Cookie is set. Now let's check that the cookie is properly cleaned.
I stop at the braakpoint and check cookie. The value is {}.
Well. All cookies seems to be cleaned.
The problem: When reloading I constantly come to the breakpoint. This means that Varnish passes the request to the backend. In other words if (req.http.Cookie) not working as I expect. I expect that at the previous step I have removed cookies. Then I check if cookies exist. And there shouldn't be any.
Could you help me:
Understand what is going on here.
Organize everything so that I should definitely remove cookies if I have removed them incorrectly.
Make Varnish serve this request from cache without passing it to the backend.
==============ADDED ON 16th of APRIL================= +++++++++++++++++++++++++++++++++++++++++++++++++++++
I have upgraded Varnish to 6.4:
michael@michael:~$ varnishd -V
varnishd (varnish-6.4.0 revision 13f137934ec1cf14af66baf7896311115ee35598)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2020 Varnish Software AS
What we are going to test:
Then I organized nginx behind Varnish (only to log requests). Nginx listens at 8090. This is log config:
log_format main '[$time_local] $http_cookie';
Cookies:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
If we don't cut cookies, the log looks this (this is just for COMPARISON):
127.0.0.1 - - [16/Apr/2020:08:11:05 +0300] "GET / HTTP/1.1" sort_on=title; _ga=GA1.1.236170900.1587013419; _gid=GA1.1.2033785209.1587013419 200 334 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" "127.0.0.1"
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
varnish.ctl
vcl 4.1;
import cookie;
backend default {
.host = "127.0.0.1";
.port = "8090";
}
sub vcl_recv {
unset req.http.Cookie;
if (req.http.Cookie) {
return (pass);
}
}
Nginx passes requests to the backend. Backend is at port 8080.
In short what listens where:
Varnish - 8000
Nginx - 8090
Backend - 8080
Start varnishd:
michael@michael:~$ sudo varnishd -f /home/michael/PycharmProjects/varnish/varnish.vcl -a localhost:8000
Open Chrome, load the page several times:
Nginx's access log:
127.0.0.1 - - [16/Apr/2020:08:12:49 +0300] "GET / HTTP/1.1" - 200 334 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" "127.0.0.1"
127.0.0.1 - - [16/Apr/2020:08:13:21 +0300] "GET / HTTP/1.1" - 200 334 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36" "127.0.0.1"
We can see that cookie is absent. It is Ok. Cookies are cut off.
Problem: Requests are inevitably passed to the backend. I always stop at the breakpoint.
Will you be so kind as to give me a piece of advice on how to cope with the problem?
Upvotes: 0
Views: 537
Reputation: 4808
Varnish doesn't look at the contents of the Cookie
request header, but rather checks if the header is present.
What you need to do is to check if the Cookie
header is empty, and if so, just remove the entire thing.
Just add this after your regsub
statement:
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
In reality you'll probably will not remove all cookies, but just the ones that are not essential to your application.
You can use this statement to remove all cookies, except that ones you need for your application:
sub vcl_recv {
if (req.http.Cookie) {
set req.http.Cookie = ";" + req.http.Cookie;
set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
set req.http.Cookie = regsuball(req.http.Cookie,
";(SESS[a-z0-9]+|NO_CACHE)=", "; \1=");
set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
else {
return (pass);
}
}
}
This snippet will remove all cookies, expect that ones that match the SESS[a-z0-9]+|NO_CACHE
regex.
vmod_cookie
There is a cleaner way to approach cookie substitution in Varnish and it involves using the vmod_cookie
module in Varnish. You can find it here: https://github.com/varnishcache/varnish-cache/tree/master/lib/libvmod_cookie
If you upgrade to Varnish version 6.4, the vmod_cookie
will be part of the core Varnish installation.
This is the equivalent using vmod_cookie
:
vcl 4.1;
import cookie;
sub vcl_recv {
cookie.parse(req.http.cookie);
cookie.keep_re("SESS[a-z0-9]+,NO_CACHE");
set req.http.cookie = cookie.get_string();
if (req.http.cookie ~ "^\s*$") {
unset req.http.cookie;
}
}
Upvotes: 4