Search code examples
varnishvarnish-vclvarnish-4

Varnish response based on Cookie


I have the following Varnish configuration:


# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_hash {

    if (req.http.cookie ~ "wordpress_logged_in_[a-z0-9]+") {
        set req.http.X-TMP = regsuball(req.http.cookie, "wordpress_logged_in_[a-z0-9]+=[^;]+(; )?", "; \1=");
        hash_data(req.http.X-TMP);
        unset req.http.X-TMP;
  }

}

sub vcl_recv {

    #Admin Area
    if (req.url ~ "wp-admin|wp-login") {
        return (pass);
    }


    #woocommerce specifics
    if (req.url ~ "^/(cart|my-account|checkout|addons)") {
        return (pass);
    }

    if ( req.url ~ "\?add-to-cart=" ) {
        return (pass);
    }


    set req.http.cookie = regsuball(req.http.cookie, "wp-settings-\d+=[^;]+(; )?", "");
    set req.http.cookie = regsuball(req.http.cookie, "wp-settings-time-\d+=[^;]+(; )?", "");
    set req.http.cookie = regsuball(req.http.cookie, "wordpress_test_cookie=[^;]+(; )?", "");
    #set req.http.cookie = regsuball(req.http.cookie, "wordpress_logged_in_[a-z0-9]+=[^;]+(; )?", "; \1=");

    #more woocommerce specifics

    # Unset Cookies except for WordPress admin and WooCommerce pages
    if (!(req.url ~ "(wp-login|wp-admin|cart|my-account/*|wc-api*|checkout|addons|logout|lost-password|product/*)")) {
        unset req.http.cookie;
    }

    # Pass through the WooCommerce dynamic pages
    if (req.url ~ "^/(cart|my-account/*|checkout|wc-api/*|addons|logout|lost-password|product/*)") {
        return (pass);
    }

    # Pass through the WooCommerce add to cart
    if (req.url ~ "\?add-to-cart=" ) {
        return (pass);
    }

    # Pass through the WooCommerce API
    if (req.url ~ "\?wc-api=" ) {
        return (pass);
    }

    if (req.http.cookie == "") {

        unset req.http.cookie;
    }

    return(hash);
}


sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.

    if (beresp.ttl == 120s) {

        set beresp.ttl = 1h;

    }

    #set beresp.http.host = bereq.http.host;
}

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.
}

My goal is to ensure that I have two different cached versions on URL's based on wether or not the user is logged in. I can determine that by a cookie that is named like wordpress_logged_in_[some id].

I've attempted to find inspiration for this in this article, but I am unable to get two different results based on whether or not the client has the cookie mentioned before. To me, it appears like it's the same cached content presented regardless of the cookie's presence.

I'd appreciate some help on understanding my issue.


Solution

  • Applying the solution that was suggested in the article will yield as many cache entries as there are logged in users (per-user cache).

    If you want one cache object for guest and the other for all logged in users, then hash on a "boolean" which is set based of presence of the cookie:

    sub vcl_hash {
      if (req.http.cookie ~ "wordpress_logged_in_") {
        hash_data("wordpress_logged_in");
      }
      # the builtin.vcl will take care of also varying cache on Host/IP and URL 
    }
    

    This will be only safe if in presence of the cookie the generated page doesn't bare user-specific content. For example, if "logged in page" is different from "logged out page" only by the presence of "Log out" text in the header section of the site.

    Anywhere the content is absolutely user-specific, you don't want to apply such logic. For example, "Hi, John" in the header text.