1

I've created the following observer method that sets a cookie:

       if ($this->_cookieManager->getCookie(self::COOKIE_NAME)) {
            $this->_cookieManager->deleteCookie(
                self::COOKIE_NAME,
                $this->_cookieMetadataFactory
                    ->createCookieMetadata()
                    ->setPath('/')
                    ->setDomain(null)
            );
        }

        $metadata = $this->_cookieMetadataFactory
            ->createPublicCookieMetadata()
            ->setDuration(self::COOKIE_DURATION)
            ->setPath('/')
            ->setDomain(null);

        $this->_cookieManager->setPublicCookie(
            self::COOKIE_NAME,
            $mediumValue,
            $metadata
        );

It observes the event controller_action_predispatch to run on all pages. This code works perfectly when Varnish is disabled, but when I enable varnish, this code no longer sets the new cookie.

1 Answer 1

1

The standard VCL code for Magento actively removes Set-Cookie headers from pages otherwise cacheable pages.

Here's some relevant VCL code from the Varnish Developer portal for dealing with responses prior to storing them in the cache:

# Only cache HTTP 200 & HTTP 404 responses
if (beresp.status != 200 && beresp.status != 404) {
    set beresp.ttl = 120s;
    set beresp.uncacheable = true;
    return (deliver);
# Don't cache private responses
} elsif (beresp.http.Cache-Control ~ "private") {
    set beresp.uncacheable = true;
    set beresp.ttl = 86400s;
    return (deliver);
}

# Remove the Set-Cookie header for cacheable content
# Only for HTTP GET & HTTP HEAD requests
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
    unset beresp.http.set-cookie;
}

As you can see, the standard VCL code will strip off all Set-Cookie headers for cacheable content that was triggered by an HTTP GET or HEAD request.

If the response status code is not 200 or 404, or when there's a Cache-Control: private header set, Varnish will keep the Set-Cookie in the response.

The solution is to add the Cache-Control: private header to the response that sets the cookie.

7
  • Don't you think removing unset beresp.http.set-cookie; is a better solution?
    – AboElnouR
    Commented Oct 26, 2022 at 13:42
  • @AboElnouR you could try that, but I'm afraid there will be responses where Magento sends responses that include an unwanted Set-Cookie. Please try and check if your hit rate is still acceptable. Commented Oct 26, 2022 at 20:24
  • Can't I create a condition if I have an exact query to pass this statement?
    – AboElnouR
    Commented Oct 27, 2022 at 11:26
  • @AboElnouR let me know what the condition is and what action to execute and I'll update my answer with the updated VCL Commented Oct 27, 2022 at 15:07
  • 1
    @AboElnouR In theory a Cache-Control: no-cache should work, but Magento seems to override this behavior in the VCL file and prefer Cache-Control: private instead. Maybe your VCL file looks slightly different. In terms of best-practices, setting a cookie changes state, so having a Cache-Control: private, no-cache, no-store is the way to go. Any variant of that Cache-Control header that prevents caching is also good. Commented Oct 31, 2022 at 13:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.