diff --git a/Helper/VclGenerator.php b/Helper/VclGenerator.php
index e4bff4a..a2c5288 100644
--- a/Helper/VclGenerator.php
+++ b/Helper/VclGenerator.php
@@ -25,11 +25,13 @@ class VclGenerator extends AbstractHelper {
private $magentoEdition;
private $magentoVersion;
private $moduleVersion;
+ protected $scopeConfig;
function __construct (
Data $data,
LazyVclParser $parser,
- ProductMetadataInterface $metadata
+ ProductMetadataInterface $metadata,
+ ScopeConfigInterface $scopeConfig
) {
$this->data = $data;
$this->parser = $parser;
@@ -37,6 +39,7 @@ function __construct (
$this->magentoVersion = $this->metadata->getVersion ();
$this->magentoEdition = $this->metadata->getEdition ();
$this->moduleVersion = $this->data->getModuleVersion ();
+ $this->scopeConfig = $scopeConfig;
}
public function insertSubHooksInclude ( $root ) {
@@ -216,6 +219,67 @@ public function versionEndpoint ( $node ) {
return $node;
}
+public function insertXkey($node) {
+ $isXkeyEnabled = $this->scopeConfig->getValue(
+ 'system/full_page_cache/varnish/enable_xkey',
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+ $isSoftPurgingUsed = $this->scopeConfig->getValue(
+ 'system/full_page_cache/varnish/use_soft_purging',
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+
+ if (!$isXkeyEnabled || !$isSoftPurgingUsed) {
+ return $node;
+ }
+
+ if ($node["type"] == "import" && strpos($node["raw"], "import std;") !== false) {
+ $importXkey = "import xkey;\n";
+ if (strpos($node["value"], $importXkey) === false) {
+ $node["value"] .= $importXkey;
+ $node["raw"] .= $importXkey;
+ }
+ return $node;
+ }
+
+ if ($node["type"] == "sub" && $node["identifier"] == "vcl_recv") {
+ $value = implode("\n", [
+ " # Full Page Cache flush",
+ " if (req.http.X-Magento-Tags-Pattern == \".*\") {",
+ " ban(\"obj.http.X-Magento-Tags ~ \" + req.http.X-Magento-Tags-Pattern);",
+ " } elseif (req.http.X-Magento-Tags-Pattern) {",
+ " set req.http.X-Magento-Tags-Pattern = regsuball(req.http.X-Magento-Tags-Pattern, \"[^a-zA-Z0-9_-]+\", \" \");",
+ " set req.http.X-Magento-Tags-Pattern = regsuball(req.http.X-Magento-Tags-Pattern, \"(^\\s*)|(\\s*$)\", \"\");",
+ " set req.http.n-gone = xkey.softpurge(req.http.X-Magento-Tags-Pattern);",
+ " return (synth(200, \"Invalidated \" + req.http.n-gone + \" objects\"));",
+ " }",
+ ]);
+
+ $value = "\n$value\n" . $node["value"];
+ $raw = "sub " . $node["identifier"] . " {\n" . $value . "\n}";
+ $node["value"] = $value;
+ $node["raw"] = $raw;
+ }
+
+ if ($node["type"] == "sub" && $node["identifier"] == "vcl_backend_response") {
+ $value = implode("\n", [
+ " set beresp.grace = 3h;",
+ " if (beresp.http.X-Magento-Tags) {",
+ " set beresp.http.Grace = beresp.grace;",
+ " set beresp.http.xkey = regsuball(beresp.http.X-Magento-Tags, \",\", \" \");",
+ " set beresp.http.X-Magento-Tags = \"fpc\";",
+ " }",
+ ]);
+
+ $value = "\n$value\n" . $node["value"];
+ $raw = "sub " . $node["identifier"] . " {\n" . $value . "\n}";
+ $node["value"] = $value;
+ $node["raw"] = $raw;
+ }
+
+ return $node;
+}
+
function generateDefault ( $vcl ) {
$this->parser->setData ( $vcl );
$root = $this->parser->getAST ();
@@ -230,6 +294,7 @@ function generateDefault ( $vcl ) {
$root = $this->parser->visit ( $root, [ $this, "insertDeliver" ] );
$root = $this->parser->visit ( $root, [ $this, "insertSubHooks" ] );
$root = $this->insertSubHooksInclude ( $root );
+ $root = $this->parser->visit($root, [$this, "insertXkey"]);
return $this->parser->getString ( $root );
}
diff --git a/conf/varnish/default.vcl b/conf/varnish/default.vcl
index 586b97a..c8d5cb9 100644
--- a/conf/varnish/default.vcl
+++ b/conf/varnish/default.vcl
@@ -1,6 +1,42 @@
vcl 4.1;
+{{if enable_xkey}}
+import xkey;
+{{/if}}
+
backend default {
.host = "magento";
.port = "8080";
}
+
+sub vcl_recv {
+ {{if enable_xkey}}
+ # Full Page Cache flush
+ if (req.http.X-Magento-Tags-Pattern == ".*") {
+ ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
+ } elseif (req.http.X-Magento-Tags-Pattern) {
+ # replace "((^|,)cat_c(,|$))|((^|,)cat_p(,|$))" to be "cat_c cat_p"
+ set req.http.X-Magento-Tags-Pattern = regsuball(req.http.X-Magento-Tags-Pattern, "[^a-zA-Z0-9_-]+" ," ");
+ # trim spaces
+ set req.http.X-Magento-Tags-Pattern = regsuball(req.http.X-Magento-Tags-Pattern, "(^\s*)|(\s*$)" ,"");
+ set req.http.n-gone = xkey.softpurge(req.http.X-Magento-Tags-Pattern);
+ return (synth(200, "Invalidated " + req.http.n-gone + " objects"));
+ }
+ {{/if}}
+}
+
+sub vcl_backend_response {
+ # Period to allow stale cache to be served
+ set beresp.grace = 3h;
+
+ {{if enable_xkey}}
+ # using xkey
+ if (beresp.http.X-Magento-Tags) {
+ set beresp.http.Grace = beresp.grace;
+ # set space separated xkey
+ set beresp.http.xkey = regsuball(beresp.http.X-Magento-Tags, ",", " ");
+ # reset beresp.http.X-Magento-Tags with some common general value
+ set beresp.http.X-Magento-Tags = "fpc";
+ }
+ {{/if}}
+}
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index fdcf27d..5405fe9 100644
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -26,6 +26,22 @@
1
+
+
+ Varnish VMOD xkey.]]>
+ Magento\Config\Model\Config\Source\Yesno
+
+ 2
+
+
+
+
+ Use soft purging instead of hard purging. This requires Xkey vmod to be installed
+ Magento\Config\Model\Config\Source\Yesno
+
+ 1
+
+
2
diff --git a/etc/config.xml b/etc/config.xml
index f0b4c86..7cc4c24 100644
--- a/etc/config.xml
+++ b/etc/config.xml
@@ -13,6 +13,7 @@
+ 0