Skip to content

Commit 1f7a78a

Browse files
committed
Merge branch 'ACP2E-2102' of https://github.com/magento-l3/magento2ce into 04-29-24-Tier4-Bugfix-Delivery
2 parents 9ab406b + 771173f commit 1f7a78a

File tree

8 files changed

+368
-0
lines changed

8 files changed

+368
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2023 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\PageCache\Block\System\Config\Form\Field\Export;
20+
21+
class Varnish7 extends \Magento\PageCache\Block\System\Config\Form\Field\Export
22+
{
23+
/**
24+
* Return Varnish version to this class
25+
*
26+
* @return int
27+
*/
28+
public function getVarnishVersion()
29+
{
30+
return 7;
31+
}
32+
}

app/code/Magento/PageCache/Controller/Adminhtml/PageCache/ExportVarnishConfig.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public function execute()
5353
$fileName = 'varnish.vcl';
5454
$varnishVersion = $this->getRequest()->getParam('varnish');
5555
switch ($varnishVersion) {
56+
case 7:
57+
$content = $this->config->getVclFile(\Magento\PageCache\Model\Config::VARNISH_7_CONFIGURATION_PATH);
58+
break;
5659
case 6:
5760
$content = $this->config->getVclFile(\Magento\PageCache\Model\Config::VARNISH_6_CONFIGURATION_PATH);
5861
break;

app/code/Magento/PageCache/Model/Config.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class Config
5151
*/
5252
protected $_scopeConfig;
5353

54+
/**
55+
* XML path to Varnish 7 config template path
56+
*/
57+
public const VARNISH_7_CONFIGURATION_PATH = 'system/full_page_cache/varnish7/path';
58+
5459
/**
5560
* XML path to Varnish 6 config template path
5661
*/
@@ -155,6 +160,9 @@ public function getVclFile($vclTemplatePath)
155160
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
156161
);
157162
switch ($vclTemplatePath) {
163+
case self::VARNISH_7_CONFIGURATION_PATH:
164+
$version = 7;
165+
break;
158166
case self::VARNISH_6_CONFIGURATION_PATH:
159167
$version = 6;
160168
break;

app/code/Magento/PageCache/Model/Varnish/VclTemplateLocator.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\Framework\Module\Dir\Reader;
1212
use Magento\Framework\Filesystem\DirectoryList;
1313
use Magento\Framework\Filesystem\Directory\ReadFactory;
14+
use Magento\PageCache\Model\Config;
1415
use Magento\PageCache\Model\VclTemplateLocatorInterface;
1516
use Magento\PageCache\Exception\UnsupportedVarnishVersion;
1617

@@ -56,11 +57,17 @@ class VclTemplateLocator implements VclTemplateLocatorInterface
5657
*/
5758
public const VARNISH_SUPPORTED_VERSION_6 = '6';
5859

60+
/**
61+
* Varnish 7 supported version
62+
*/
63+
public const VARNISH_SUPPORTED_VERSION_7 = '7';
64+
5965
/**
6066
* @var array
6167
*/
6268
private $supportedVarnishVersions = [
6369
self::VARNISH_SUPPORTED_VERSION_6 => self::VARNISH_6_CONFIGURATION_PATH,
70+
self::VARNISH_SUPPORTED_VERSION_7 => Config::VARNISH_7_CONFIGURATION_PATH,
6471
];
6572

6673
/**

app/code/Magento/PageCache/etc/adminhtml/system.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
<field id="caching_application">1</field>
5656
</depends>
5757
</field>
58+
<field id="export_button_version7" type="button" sortOrder="40" showInDefault="1">
59+
<frontend_model>Magento\PageCache\Block\System\Config\Form\Field\Export\Varnish7</frontend_model>
60+
<depends>
61+
<field id="caching_application">1</field>
62+
</depends>
63+
</field>
5864
<depends>
5965
<field id="caching_application">2</field>
6066
</depends>

app/code/Magento/PageCache/etc/config.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
</design>
1515
<system>
1616
<full_page_cache>
17+
<varnish7>
18+
<path>varnish7.vcl</path>
19+
</varnish7>
1720
<varnish6>
1821
<path>varnish6.vcl</path>
1922
</varnish6>
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# VCL version 5.0 is not supported so it should be 4.0 even though actually used Varnish version is 7
2+
vcl 4.0;
3+
4+
import std;
5+
# The minimal Varnish version is 7.0
6+
# For SSL offloading, pass the following header in your proxy server or load balancer: '/* {{ ssl_offloaded_header }} */: https'
7+
8+
backend default {
9+
.host = "/* {{ host }} */";
10+
.port = "/* {{ port }} */";
11+
.first_byte_timeout = 600s;
12+
.probe = {
13+
.url = "/health_check.php";
14+
.timeout = 2s;
15+
.interval = 5s;
16+
.window = 10;
17+
.threshold = 5;
18+
}
19+
}
20+
21+
acl purge {
22+
/* {{ ips }} */
23+
}
24+
25+
sub vcl_recv {
26+
if (req.restarts > 0) {
27+
set req.hash_always_miss = true;
28+
}
29+
30+
if (req.method == "PURGE") {
31+
if (client.ip !~ purge) {
32+
return (synth(405, "Method not allowed"));
33+
}
34+
# To use the X-Pool header for purging varnish during automated deployments, make sure the X-Pool header
35+
# has been added to the response in your backend server config. This is used, for example, by the
36+
# capistrano-magento2 gem for purging old content from varnish during it's deploy routine.
37+
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
38+
return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required"));
39+
}
40+
if (req.http.X-Magento-Tags-Pattern) {
41+
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
42+
}
43+
if (req.http.X-Pool) {
44+
ban("obj.http.X-Pool ~ " + req.http.X-Pool);
45+
}
46+
return (synth(200, "Purged"));
47+
}
48+
49+
if (req.method != "GET" &&
50+
req.method != "HEAD" &&
51+
req.method != "PUT" &&
52+
req.method != "POST" &&
53+
req.method != "TRACE" &&
54+
req.method != "OPTIONS" &&
55+
req.method != "DELETE") {
56+
/* Non-RFC2616 or CONNECT which is weird. */
57+
return (pipe);
58+
}
59+
60+
# We only deal with GET and HEAD by default
61+
if (req.method != "GET" && req.method != "HEAD") {
62+
return (pass);
63+
}
64+
65+
# Bypass customer, shopping cart, checkout
66+
if (req.url ~ "/customer" || req.url ~ "/checkout") {
67+
return (pass);
68+
}
69+
70+
# Bypass health check requests
71+
if (req.url ~ "^/(pub/)?(health_check.php)$") {
72+
return (pass);
73+
}
74+
75+
# Set initial grace period usage status
76+
set req.http.grace = "none";
77+
78+
# normalize url in case of leading HTTP scheme and domain
79+
set req.url = regsub(req.url, "^http[s]?://", "");
80+
81+
# collect all cookies
82+
std.collect(req.http.Cookie);
83+
84+
# Remove all marketing get parameters to minimize the cache objects
85+
if (req.url ~ "(\?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") {
86+
set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
87+
set req.url = regsub(req.url, "[?|&]+$", "");
88+
}
89+
90+
# Static files caching
91+
if (req.url ~ "^/(pub/)?(media|static)/") {
92+
# Static files should not be cached by default
93+
return (pass);
94+
95+
# But if you use a few locales and don't use CDN you can enable caching static files by commenting previous line (#return (pass);) and uncommenting next 3 lines
96+
#unset req.http.Https;
97+
#unset req.http./* {{ ssl_offloaded_header }} */;
98+
#unset req.http.Cookie;
99+
}
100+
101+
# Bypass authenticated GraphQL requests without a X-Magento-Cache-Id
102+
if (req.url ~ "/graphql" && !req.http.X-Magento-Cache-Id && req.http.Authorization ~ "^Bearer") {
103+
return (pass);
104+
}
105+
106+
return (hash);
107+
}
108+
109+
sub vcl_hash {
110+
if ((req.url !~ "/graphql" || !req.http.X-Magento-Cache-Id) && req.http.cookie ~ "X-Magento-Vary=") {
111+
hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
112+
}
113+
114+
# To make sure http users don't see ssl warning
115+
if (req.http./* {{ ssl_offloaded_header }} */) {
116+
hash_data(req.http./* {{ ssl_offloaded_header }} */);
117+
}
118+
/* {{ design_exceptions_code }} */
119+
120+
if (req.url ~ "/graphql") {
121+
call process_graphql_headers;
122+
}
123+
}
124+
125+
sub process_graphql_headers {
126+
if (req.http.X-Magento-Cache-Id) {
127+
hash_data(req.http.X-Magento-Cache-Id);
128+
129+
# When the frontend stops sending the auth token, make sure users stop getting results cached for logged-in users
130+
if (req.http.Authorization ~ "^Bearer") {
131+
hash_data("Authorized");
132+
}
133+
}
134+
135+
if (req.http.Store) {
136+
hash_data(req.http.Store);
137+
}
138+
139+
if (req.http.Content-Currency) {
140+
hash_data(req.http.Content-Currency);
141+
}
142+
}
143+
144+
sub vcl_backend_response {
145+
146+
set beresp.grace = 3d;
147+
148+
if (beresp.http.content-type ~ "text") {
149+
set beresp.do_esi = true;
150+
}
151+
152+
if (bereq.url ~ "\.js$" || beresp.http.content-type ~ "text") {
153+
set beresp.do_gzip = true;
154+
}
155+
156+
if (beresp.http.X-Magento-Debug) {
157+
set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
158+
}
159+
160+
# cache only successfully responses and 404s that are not marked as private
161+
if ((beresp.status != 200 && beresp.status != 404) || beresp.http.Cache-Control ~ "private") {
162+
set beresp.uncacheable = true;
163+
set beresp.ttl = 86400s;
164+
return (deliver);
165+
}
166+
167+
# validate if we need to cache it and prevent from setting cookie
168+
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
169+
# Collapse beresp.http.set-cookie in order to merge multiple set-cookie headers
170+
# Although it is not recommended to collapse set-cookie header,
171+
# it is safe to do it here as the set-cookie header is removed below
172+
std.collect(beresp.http.set-cookie);
173+
# Do not cache the response under current cache key (hash),
174+
# if the response has X-Magento-Vary but the request does not.
175+
if ((bereq.url !~ "/graphql" || !bereq.http.X-Magento-Cache-Id)
176+
&& bereq.http.cookie !~ "X-Magento-Vary="
177+
&& beresp.http.set-cookie ~ "X-Magento-Vary=") {
178+
set beresp.ttl = 0s;
179+
set beresp.uncacheable = true;
180+
}
181+
unset beresp.http.set-cookie;
182+
}
183+
184+
# If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass
185+
if (beresp.ttl <= 0s ||
186+
beresp.http.Surrogate-control ~ "no-store" ||
187+
(!beresp.http.Surrogate-Control &&
188+
beresp.http.Cache-Control ~ "no-cache|no-store") ||
189+
beresp.http.Vary == "*") {
190+
# Mark as Hit-For-Pass for the next 2 minutes
191+
set beresp.ttl = 120s;
192+
set beresp.uncacheable = true;
193+
}
194+
195+
# If the cache key in the Magento response doesn't match the one that was sent in the request, don't cache under the request's key
196+
if (bereq.url ~ "/graphql" && bereq.http.X-Magento-Cache-Id && bereq.http.X-Magento-Cache-Id != beresp.http.X-Magento-Cache-Id) {
197+
set beresp.ttl = 0s;
198+
set beresp.uncacheable = true;
199+
}
200+
201+
return (deliver);
202+
}
203+
204+
sub vcl_deliver {
205+
if (obj.uncacheable) {
206+
set resp.http.X-Magento-Cache-Debug = "UNCACHEABLE";
207+
} else if (obj.hits) {
208+
set resp.http.X-Magento-Cache-Debug = "HIT";
209+
set resp.http.Grace = req.http.grace;
210+
} else {
211+
set resp.http.X-Magento-Cache-Debug = "MISS";
212+
}
213+
214+
# Not letting browser to cache non-static files.
215+
if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
216+
set resp.http.Pragma = "no-cache";
217+
set resp.http.Expires = "-1";
218+
set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
219+
}
220+
221+
if (!resp.http.X-Magento-Debug) {
222+
unset resp.http.Age;
223+
}
224+
unset resp.http.X-Magento-Debug;
225+
unset resp.http.X-Magento-Tags;
226+
unset resp.http.X-Powered-By;
227+
unset resp.http.Server;
228+
unset resp.http.X-Varnish;
229+
unset resp.http.Via;
230+
unset resp.http.Link;
231+
}
232+
233+
sub vcl_hit {
234+
if (obj.ttl >= 0s) {
235+
# Hit within TTL period
236+
return (deliver);
237+
}
238+
if (std.healthy(req.backend_hint)) {
239+
if (obj.ttl + /* {{ grace_period }} */s > 0s) {
240+
# Hit after TTL expiration, but within grace period
241+
set req.http.grace = "normal (healthy server)";
242+
return (deliver);
243+
} else {
244+
# Hit after TTL and grace expiration
245+
return (restart);
246+
}
247+
} else {
248+
# server is not healthy, retrieve from cache
249+
set req.http.grace = "unlimited (unhealthy server)";
250+
return (deliver);
251+
}
252+
}

0 commit comments

Comments
 (0)