forked from ezsystems/ezpublish-community
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request ezsystems#198 from ezsystems/impl_EZP-22400_FOSHtt…
…pCacheBundle EZP-22400: Use FOSHttpCacheBundle
- Loading branch information
Showing
5 changed files
with
435 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# eZ Publish Varnish configuration | ||
|
||
## Prerequisites | ||
* A working Varnish 3 or Varnish 4 setup. | ||
|
||
## Recommended VCL base files | ||
For Varnish to work properly with eZ, you'll need to use one of the provided files as a basis: | ||
|
||
* [eZ 5.4+ / 2014.09+ with Varnish 3](vcl/varnish3.vcl) | ||
* [eZ 5.4+ / 2014.09+ with Varnish 4](vcl/varnish4.vcl) | ||
|
||
> **Note:** Http cache management is done with the help of [FOSHttpCacheBundle](http://foshttpcachebundle.readthedocs.org/). | ||
One may need to tweak their VCL further on according to [FOSHttpCache documentation](http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html) | ||
in order to use features supported by it. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
// Varnish 3 style - eZ 5.4+ / 2014.09+ | ||
// Complete VCL example | ||
|
||
// Our Backend - Assuming that web server is listening on port 80 | ||
// Replace the host to fit your setup | ||
backend ezpublish { | ||
.host = "127.0.0.1"; | ||
.port = "80"; | ||
} | ||
|
||
// ACL for invalidators IP | ||
acl invalidators { | ||
"127.0.0.1"; | ||
"192.168.0.0"/16; | ||
} | ||
|
||
// ACL for debuggers IP | ||
acl debuggers { | ||
"127.0.0.1"; | ||
"192.168.0.0"/16; | ||
} | ||
|
||
// Called at the beginning of a request, after the complete request has been received | ||
sub vcl_recv { | ||
|
||
// Set the backend | ||
set req.backend = ezpublish; | ||
|
||
// Advertise Symfony for ESI support | ||
set req.http.Surrogate-Capability = "abc=ESI/1.0"; | ||
|
||
// Add a unique header containing the client address (only for master request) | ||
// Please note that /_fragment URI can change in Symfony configuration | ||
if (!req.url ~ "^/_fragment") { | ||
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; | ||
} | ||
} | ||
|
||
// Trigger cache purge if needed | ||
call ez_purge; | ||
|
||
// Don't cache requests other than GET and HEAD. | ||
if (req.request != "GET" && req.request != "HEAD") { | ||
return (pass); | ||
} | ||
|
||
// Normalize the Accept-Encoding headers | ||
if (req.http.Accept-Encoding) { | ||
if (req.http.Accept-Encoding ~ "gzip") { | ||
set req.http.Accept-Encoding = "gzip"; | ||
} elsif (req.http.Accept-Encoding ~ "deflate") { | ||
set req.http.Accept-Encoding = "deflate"; | ||
} else { | ||
unset req.http.Accept-Encoding; | ||
} | ||
} | ||
|
||
// Don't cache Authenticate & Authorization | ||
// You may remove this when using REST API with basic auth. | ||
if (req.http.Authenticate || req.http.Authorization) { | ||
if (client.ip ~ debuggers) { | ||
set req.http.X-Debug = "Not Cached according to configuration (Authorization)"; | ||
} | ||
return(pass); | ||
} | ||
|
||
// Do a standard lookup on assets | ||
// Note that file extension list below is not extensive, so consider completing it to fit your needs. | ||
if (req.url ~ "\.(css|js|gif|jpe?g|bmp|png|tiff?|ico|img|tga|wmf|svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|zip|gz|pdf|ttf|eot|wof)$") { | ||
return (lookup); | ||
} | ||
|
||
// Retrieve client user hash and add it to the forwarded request. | ||
call ez_user_hash; | ||
|
||
// If it passes all these tests, do a lookup anyway. | ||
return (lookup); | ||
} | ||
|
||
// Called when the requested object has been retrieved from the backend | ||
sub vcl_fetch { | ||
|
||
if (req.restarts == 0 | ||
&& req.http.accept ~ "application/vnd.fos.user-context-hash" | ||
&& beresp.status >= 500 | ||
) { | ||
error 503 "Hash error"; | ||
} | ||
|
||
// Optimize to only parse the Response contents from Symfony | ||
if (beresp.http.Surrogate-Control ~ "ESI/1.0") { | ||
unset beresp.http.Surrogate-Control; | ||
set beresp.do_esi = true; | ||
} | ||
|
||
// Respect the Cache-Control=private header from the backend | ||
if (beresp.http.Cache-Control ~ "no-cache|no-store|private") { | ||
set beresp.ttl = 120s; | ||
return (hit_for_pass); | ||
} | ||
|
||
return (deliver); | ||
} | ||
|
||
// Handle purge | ||
// You may add FOSHttpCacheBundle tagging rules | ||
// See http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html#id4 | ||
sub ez_purge { | ||
|
||
if (req.request == "BAN") { | ||
if (!client.ip ~ invalidators) { | ||
error 405 "Method not allowed"; | ||
} | ||
|
||
if (req.http.X-Location-Id) { | ||
ban( "obj.http.X-Location-Id ~ " + req.http.X-Location-Id); | ||
if (client.ip ~ debuggers) { | ||
set req.http.X-Debug = "Ban done for content connected to LocationId " + req.http.X-Location-Id; | ||
} | ||
error 200 "Banned"; | ||
} | ||
} | ||
} | ||
|
||
// Sub-routine to get client user hash, for context-aware HTTP cache. | ||
sub ez_user_hash { | ||
|
||
// Prevent tampering attacks on the hash mechanism | ||
if (req.restarts == 0 | ||
&& (req.http.accept ~ "application/vnd.fos.user-context-hash" | ||
|| req.http.x-user-hash | ||
) | ||
) { | ||
error 400; | ||
} | ||
|
||
if (req.restarts == 0 && (req.request == "GET" || req.request == "HEAD")) { | ||
// Anonymous user => Set a hardcoded anonymous hash | ||
if (req.http.Cookie !~ "eZSESSID" && !req.http.authorization) { | ||
set req.http.X-User-Hash = "38015b703d82206ebc01d17a39c727e5"; | ||
} | ||
// Pre-authenticate request to get shared cache, even when authenticated | ||
else { | ||
set req.http.x-fos-original-url = req.url; | ||
set req.http.x-fos-original-accept = req.http.accept; | ||
set req.http.x-fos-original-cookie = req.http.cookie; | ||
// Clean up cookie for the hash request to only keep session cookie, as hash cache will vary on cookie. | ||
set req.http.cookie = ";" + req.http.cookie; | ||
set req.http.cookie = regsuball(req.http.cookie, "; +", ";"); | ||
set req.http.cookie = regsuball(req.http.cookie, ";(eZSESSID[^=]*)=", "; \1="); | ||
set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", ""); | ||
set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", ""); | ||
|
||
set req.http.accept = "application/vnd.fos.user-context-hash"; | ||
set req.url = "/_fos_user_context_hash"; | ||
|
||
// Force the lookup, the backend must tell how to cache/vary response containing the user hash | ||
|
||
return (lookup); | ||
} | ||
} | ||
|
||
// Rebuild the original request which now has the hash. | ||
if (req.restarts > 0 | ||
&& req.http.accept == "application/vnd.fos.user-context-hash" | ||
) { | ||
set req.url = req.http.x-fos-original-url; | ||
set req.http.accept = req.http.x-fos-original-accept; | ||
set req.http.cookie = req.http.x-fos-original-cookie; | ||
|
||
unset req.http.x-fos-original-url; | ||
unset req.http.x-fos-original-accept; | ||
unset req.http.x-fos-original-cookie; | ||
|
||
// Force the lookup, the backend must tell not to cache or vary on the | ||
// user hash to properly separate cached data. | ||
|
||
return (lookup); | ||
} | ||
} | ||
|
||
sub vcl_deliver { | ||
// On receiving the hash response, copy the hash header to the original | ||
// request and restart. | ||
if (req.restarts == 0 | ||
&& resp.http.content-type ~ "application/vnd.fos.user-context-hash" | ||
&& resp.status == 200 | ||
) { | ||
set req.http.x-user-hash = resp.http.x-user-hash; | ||
|
||
return (restart); | ||
} | ||
|
||
// If we get here, this is a real response that gets sent to the client. | ||
|
||
// Remove the vary on context user hash, this is nothing public. Keep all | ||
// other vary headers. | ||
set resp.http.Vary = regsub(resp.http.Vary, "(?i),? *x-user-hash *", ""); | ||
set resp.http.Vary = regsub(resp.http.Vary, "^, *", ""); | ||
if (resp.http.Vary == "") { | ||
unset resp.http.Vary; | ||
} | ||
|
||
// Sanity check to prevent ever exposing the hash to a client. | ||
unset resp.http.x-user-hash; | ||
} |
Oops, something went wrong.