Closed csdougliss closed 11 years ago
I added our customer controller to the blacklist.
How did you do this exactly? If the login URL was blacklisted it should be piped through Varnish so the extra cookies should be set. If that's not happening I think you may have added it to the blacklist wrong.
The login form posts to /vax-customer/account/loginPost/.
This is the content of the VCL file:
C{
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
static pthread_mutex_t lrand_mutex = PTHREAD_MUTEX_INITIALIZER;
void generate_uuid(char* buf) {
pthread_mutex_lock(&lrand_mutex);
long a = lrand48();
long b = lrand48();
long c = lrand48();
long d = lrand48();
pthread_mutex_unlock(&lrand_mutex);
sprintf(buf, "frontend=%08lx-%04lx-%04lx-%04lx-%04lx%08lx",
a,
b & 0xffff,
(b & ((long)0x0fff0000) >> 16) | 0x4000,
(c & 0x0fff) | 0x8000,
(c & (long)0xffff0000) >> 16,
d
);
return;
}
}C
import std;
C{
#include <syslog.h>
#include <stddef.h>
}C
sub vcl_recv {
if (req.restarts == 0) {
C{
struct timeval detail_time;
gettimeofday(&detail_time,NULL);
char start[20];
sprintf(start, "t=%lu%06lu", detail_time.tv_sec, detail_time.tv_usec);
VRT_SetHdr(sp, HDR_REQ, "\020X-Request-Start:", start, vrt_magic_string_end);
}C
}
if (req.url ~ "^/registration/form") {
return (pass);
}
}
sub vcl_error {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
if (obj.status >= 500) {
C{
FILE *fp;
fp = fopen("/var/log/varnish/error_log", "a");
if(fp != NULL) {
fprintf(fp, "Error (%s) (%s) (%s)\n",
VRT_r_req_url(sp), VRT_r_obj_response(sp), VRT_r_req_xid(sp));
fclose(fp);
} else {
syslog(LOG_INFO, "Error (%s) (%s) (%s)",
VRT_r_req_url(sp), VRT_r_obj_response(sp), VRT_r_req_xid(sp));
}
}C
}
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>
<style type="text/css">
/* Errors */
* {
margin: 0;
padding: 0;
}
.error-layout { width: 100%; max-width: 1600px; height: 100%; margin: 0 auto; padding: 0; }
.error-layout .main-container { height: 100%; }
.error-layout .main { background: url("/errors/default/images/error_background.jpg") no-repeat #fff; min-height: 590px; color: #1D2B33; float: left; }
.error-layout .col-main { width: 100%; }
.error-layout .std { margin: 100px 0 0 400px; padding-left: 270px; background: url("/errors/default/images/warning_icon.png") no-repeat 10px 0; height: 200px; }
.error-layout h3 { font-size: 400%; margin-bottom: 10px; }
.error-layout p { font-size: 180%; }
.error-layout .back { float: left; background: url("/skin/frontend/vax/uk/images/icons/left_arrow.png") no-repeat 8px center #1D2B33; height: 18px; padding: 5px 8px 5px 33px; color: #FFF; font-size: 13px; line-height: 18px; text-decoration: none; margin-top: 10px; }
/* ======================================================================================= */
</style>
</head>
<body>
<div class="page error-layout">
<div class="main-container">
<div class="main">
<div class="col-main">
<div class="std"><h3>Oops, something went wrong</h3>
<!--<h1>Error "} + obj.status + " " + obj.response + {"</h1>
<p>"} + obj.response + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + req.xid + {"</p>
<hr>-->
<p><a class="back" title="Go Back" href="javascript: history.go(-1);">Go Back</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
"};
return (deliver);
}
backend default {
.host = "127.0.0.1";
.port = "8080";
.first_byte_timeout = 300s;
.between_bytes_timeout = 300s;
}
backend admin {
.host = "127.0.0.1";
.port = "8080";
.first_byte_timeout = 21600s;
.between_bytes_timeout = 21600s;
}
acl crawler_acl {
}
acl debug_acl {
"127.0.0.1";
}
sub remove_cache_headers {
unset beresp.http.Cache-Control;
unset beresp.http.Expires;
unset beresp.http.Pragma;
unset beresp.http.Cache;
unset beresp.http.Age;
}
sub remove_double_slashes {
set req.url = regsub(req.url, "(.*)//+(.*)", "\1/\2");
}
sub generate_session {
if (req.url ~ ".*[&?]SID=([^&]+).*") {
set req.http.X-Varnish-Faked-Session = regsub(
req.url, ".*[&?]SID=([^&]+).*", "frontend=\1");
} else {
C{
char uuid_buf [50];
generate_uuid(uuid_buf);
VRT_SetHdr(sp, HDR_REQ,
"\030X-Varnish-Faked-Session:",
uuid_buf,
vrt_magic_string_end
);
}C
}
if (req.http.Cookie) {
std.collect(req.http.Cookie);
set req.http.Cookie = req.http.X-Varnish-Faked-Session +
"; " + req.http.Cookie;
} else {
set req.http.Cookie = req.http.X-Varnish-Faked-Session;
}
}
sub generate_session_expires {
C{
time_t now = time(NULL);
struct tm now_tm = *gmtime(&now);
now_tm.tm_sec += 3600;
mktime(&now_tm);
char date_buf [50];
strftime(date_buf, sizeof(date_buf)-1, "%a, %d-%b-%Y %H:%M:%S %Z", &now_tm);
VRT_SetHdr(sp, HDR_RESP,
"\031X-Varnish-Cookie-Expires:",
date_buf,
vrt_magic_string_end
);
}C
}
sub vcl_recv {
if (req.restarts == 0) {
if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
if (req.request !~ "^(GET|HEAD)$") {
return (pipe);
}
call remove_double_slashes;
if (req.http.Accept-Encoding) {
if (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} else if (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
unset req.http.Accept-Encoding;
}
}
if (!true || req.http.Authorization) {
return (pipe);
}
if (req.url ~ "^(/)(?:(?:index|litespeed)\.php/)?") {
set req.http.X-Turpentine-Secret-Handshake = "1";
if (req.url ~ "^(/)(?:(?:index|litespeed)\.php/)?admin") {
set req.backend = admin;
return (pipe);
}
if (req.http.Cookie ~ "\bcurrency=") {
set req.http.X-Varnish-Currency = regsub(
req.http.Cookie, ".*\bcurrency=([^;]*).*", "\1");
}
if (req.http.Cookie ~ "\bstore=") {
set req.http.X-Varnish-Store = regsub(
req.http.Cookie, ".*\bstore=([^;]*).*", "\1");
}
if (req.url ~ "/turpentine/esi/getBlock/") {
set req.http.X-Varnish-Esi-Method = regsub(
req.url, ".*/method/(\w+)/.*", "\1");
set req.http.X-Varnish-Esi-Access = regsub(
req.url, ".*/access/(\w+)/.*", "\1");
if (req.http.X-Varnish-Esi-Method == "esi" && req.esi_level == 0 &&
!(true || client.ip ~ debug_acl)) {
error 403 "External ESI requests are not allowed";
}
}
if (req.http.Cookie !~ "frontend=") {
if (client.ip ~ crawler_acl ||
req.http.User-Agent ~ "^(?:ApacheBench/.*|.*Googlebot.*|JoeDog/.*Siege.*|magespeedtest\.com|Nexcessnet_Turpentine/.*)$") {
set req.http.Cookie = "frontend=crawler-session";
} else {
call generate_session;
}
}
if (true &&
req.url ~ ".*\.(?:css|js|jpe?g|png|gif|ico|swf)(?=\?|&|$)") {
unset req.http.Cookie;
unset req.http.X-Varnish-Faked-Session;
return (lookup);
}
if (req.url ~ "^(/)(?:(?:index|litespeed)\.php/)?(?:admin|api|cron\.php|registration/form|vax-customer/account/loginPost)") {
return (pipe);
}
if (req.url ~ "\?.*__from_store=") {
return (pipe);
}
if (true &&
req.url ~ "(?:[?&](?:__SID|XDEBUG_PROFILE)(?=[&=]|$))") {
return (pass);
}
if (req.url ~ "[?&](utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
set req.url = regsuball(req.url, "(?:(\?)?|&)(?:utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=[^&]+", "\1");
set req.url = regsuball(req.url, "(?:(\?)&|\?$)", "\1");
}
return (lookup);
}
}
sub vcl_pipe {
unset bereq.http.X-Turpentine-Secret-Handshake;
set bereq.http.Connection = "close";
}
sub vcl_hash {
hash_data(req.url);
if (req.http.Host) {
hash_data(req.http.Host);
} else {
hash_data(server.ip);
}
hash_data(req.http.Ssl-Offloaded);
if (req.http.X-Normalized-User-Agent) {
hash_data(req.http.X-Normalized-User-Agent);
}
if (req.http.Accept-Encoding) {
hash_data(req.http.Accept-Encoding);
}
hash_data("s=" + req.http.X-Varnish-Store + "&c=" + req.http.X-Varnish-Currency);
if (req.http.X-Varnish-Esi-Access == "private" &&
req.http.Cookie ~ "frontend=") {
hash_data(regsub(req.http.Cookie, "^.*?frontend=([^;]*);*.*$", "\1"));
hash_data(req.http.User-Agent);
}
return (hash);
}
sub vcl_hit {
}
sub vcl_fetch {
set req.grace = 15s;
if (req.url ~ "^(/)(?:(?:index|litespeed)\.php/)?") {
unset beresp.http.Vary;
set beresp.do_gzip = true;
if (beresp.status != 200 && beresp.status != 404) {
set beresp.ttl = 15s;
return (hit_for_pass);
} else {
if (beresp.http.Set-Cookie) {
set beresp.http.X-Varnish-Set-Cookie = beresp.http.Set-Cookie;
unset beresp.http.Set-Cookie;
}
call remove_cache_headers;
if (beresp.http.X-Turpentine-Esi == "1") {
set beresp.do_esi = true;
}
if (beresp.http.X-Turpentine-Cache == "0") {
set beresp.ttl = 15s;
return (hit_for_pass);
} else {
if (true &&
bereq.url ~ ".*\.(?:css|js|jpe?g|png|gif|ico|swf)(?=\?|&|$)") {
set beresp.ttl = 28800s;
set beresp.http.Cache-Control = "max-age=28800";
} elseif (req.http.X-Varnish-Esi-Method) {
if (req.http.X-Varnish-Esi-Access == "private" &&
req.http.Cookie ~ "frontend=") {
set beresp.http.X-Varnish-Session = regsub(req.http.Cookie,
"^.*?frontend=([^;]*);*.*$", "\1");
}
if (req.http.X-Varnish-Esi-Method == "ajax" &&
req.http.X-Varnish-Esi-Access == "public") {
set beresp.http.Cache-Control = "max-age=" + regsub(
req.url, ".*/ttl/(\d+)/.*", "\1");
}
set beresp.ttl = std.duration(
regsub(
req.url, ".*/ttl/(\d+)/.*", "\1s"),
300s);
if (beresp.ttl == 0s) {
set beresp.ttl = 15s;
return (hit_for_pass);
}
} else {
set beresp.ttl = 3600s;
}
}
}
return (deliver);
}
}
sub vcl_deliver {
if (req.http.X-Varnish-Faked-Session) {
call generate_session_expires;
set resp.http.Set-Cookie = req.http.X-Varnish-Faked-Session +
"; expires=" + resp.http.X-Varnish-Cookie-Expires + "; path=/";
if (req.http.Host) {
set resp.http.Set-Cookie = resp.http.Set-Cookie +
"; domain=" + regsub(req.http.Host, ":\d+$", "");
}
set resp.http.Set-Cookie = resp.http.Set-Cookie + "; httponly";
unset resp.http.X-Varnish-Cookie-Expires;
}
if (true || client.ip ~ debug_acl) {
set resp.http.X-Varnish-Hits = obj.hits;
set resp.http.X-Varnish-Esi-Method = req.http.X-Varnish-Esi-Method;
set resp.http.X-Varnish-Esi-Access = req.http.X-Varnish-Esi-Access;
set resp.http.X-Varnish-Currency = req.http.X-Varnish-Currency;
set resp.http.X-Varnish-Store = req.http.X-Varnish-Store;
} else {
unset resp.http.X-Varnish;
unset resp.http.Via;
unset resp.http.X-Powered-By;
unset resp.http.Server;
unset resp.http.X-Turpentine-Cache;
unset resp.http.X-Turpentine-Esi;
unset resp.http.X-Turpentine-Flush-Events;
unset resp.http.X-Turpentine-Block;
unset resp.http.X-Varnish-Session;
unset resp.http.X-Varnish-Set-Cookie;
}
}
OK what is rather odd is that the magento normal login does not work. However, a different store using the same code does. I'm actually using the devel branch of turpentine (not 0.5.3!)
I have found the issue/solution. The store has a cookie domain set as .vaxuk.local (notice the dot at the front). We do this to share sessions/carts between sub-domains e.g. support.vaxuk.local (this is on my dev machine).
When I remove the dot, the login works normally.
Is this something that can be catered for in the vcl? The magento setup does mention using . for sub-domains is acceptable.
What's odd is that when I remove the dot and set the cookie domain to vaxuk.local in the admin, after clearing the cache and clearing my cookies.. the cookie domain is still .vaxuk.local. However the login works?
The cookie that Varnish creates is based on the Host header in the request (i.e. if you send the request to www.example.com
the domain for the cookie will be www.example.com
), Turpentine doesn't use the cookie setting in Magento because the VCL it generates doesn't really handle different settings per store yet. You can force Varnish to set the cookie with the domain as .vaxuk.local
by changing these lines in the VCL template:
if (req.http.Host) {
set resp.http.Set-Cookie = resp.http.Set-Cookie +
"; domain=" + regsub(req.http.Host, ":\d+$", "");
}
to this:
set resp.http.Set-Cookie = resp.http.Set-Cookie + "; domain=.vaxuk.local";
As a side note, IIRC using a leading . (dot) in the cookie domain makes it valid for any subdomain but not the base domain. I could be wrong about this though, but it may be related to your issue.
Thanks, I believe the problem only occurs locally and on my dev server, because on live the user gets re-redirected to www (hence why I never have the problem on a production server!).
I tested it on the production server and the result was unexpected.
Turpentine VCL created a frontend cookie with a domain name of .www.ourhost.etc But I also got a second frontend cookie created with a domain name of .ourhost.etc (as per magento settings)!
The login functionality didn't work.
I can't set the domain name in the VCL as we have multiple sites/hosts. Is there a way to strip out the www perhaps so it matches magentos? Unless in the VCL it is possible to setup a specific case, so it only strips out the www when it matches a certain string?
I can't hard code the domain name in the VCL because there are multi-stores with different URLs
This should strip the "www." from the cookie domain:
diff --git a/app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl b/app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl
index 72cd460..2d8c1bf 100644
--- a/app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl
+++ b/app/code/community/Nexcessnet/Turpentine/misc/version-3.vcl
@@ -346,7 +346,7 @@ sub vcl_deliver {
"; expires=" + resp.http.X-Varnish-Cookie-Expires + "; path=/";
if (req.http.Host) {
set resp.http.Set-Cookie = resp.http.Set-Cookie +
- "; domain=" + regsub(req.http.Host, ":\d+$", "");
+ "; domain=" + regsub(req.http.Host, "(?:www\.)?([^:]*)(?::\d+)?$", "\1");
}
set resp.http.Set-Cookie = resp.http.Set-Cookie + "; httponly";
unset resp.http.X-Varnish-Cookie-Expires;
You may need to fiddle with the regex to get it working exactly how you want.
Thanks for that, very useful. I think I will have to add a check, say if req.http.host contains vax then remove the www, spares sub-domains etc.
I was wondering - regarding the normalise host option in the admin - would it be possible to make it so that only normalizes if the req.http.host matches a certain regex? (matching all if nothing supplied)? e.g. say normalize host is turned on, the cookie domain will be set to the host_target (e.g. .vaxuk.local) if the host regex matches www.vaxuk.local, spares.vaxuk.local etc?
I was wondering - regarding the normalise host option in the admin - would it be possible to make it so that only normalizes if the req.http.host matches a certain regex?
It's not impossible but it's not something I want to add to Turpentine.
This was my solution to the problem. It appears to be a necessary one if you are sharing cookie domains with multiple stores!. It may not be the best solution, but it works for now. Another option might be instead of setting the domain to the normalize_cookie_target just have it remove whatever the sub-domain was. I might go back and change that when I get a chance.
In vcl_deliver
if (req.http.Host) {
if(req.http.Host ~ "{{normalize_cookie_regex}}") {
set resp.http.Set-Cookie = resp.http.Set-Cookie +
"; domain={{normalize_cookie_target}}";
} else {
set resp.http.Set-Cookie = resp.http.Set-Cookie +
"; domain=" + regsub(req.http.Host, ":\d+$", "");
}
}
Then in Nexcessnet_Turpentine_Model_Varnish_Configurator_Version3 I added
/**
* Get the hostname for cookie normalization
*
* @return string
*/
protected function _getNormalizeCookieTarget() {
return trim( Mage::getStoreConfig(
'turpentine_vcl/normalization/cookie_target' ) );
}
/**
* Get the regex for cookie normalization
*
* @return string
*/
protected function _getNormalizeCookieRegex() {
return trim( Mage::getStoreConfig(
'turpentine_vcl/normalization/cookie_regex' ) );
}
In _getTemplateVars()
if( Mage::getStoreConfig( 'turpentine_vcl/normalization/cookie_regex' ) ) {
$vars['normalize_cookie_regex'] = $this->_getNormalizeCookieRegex();
}
if( Mage::getStoreConfig( 'turpentine_vcl/normalization/cookie_target' ) ) {
$vars['normalize_cookie_target'] = $this->_getNormalizeCookieTarget();
}
Glad you got something that works for you.
I'm having an issue similar to a previously closed issue - ajax login (but using 0.5.3).
We have a login form that does a POST to our customer controller using AJAX. The user appears to get logged in (I checked using logs) but after a page refresh the user is not logged in.
The login post action is the same as the default magento one except that it returns some information to the page. That returns that the login was succesful but on the page refresh not so. I added our customer controller to the blacklist.
There appears to be some cookies that are not being set: