Advertisement
Guest User

Core VCL

a guest
Oct 3rd, 2016
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 18.31 KB | None | 0 0
  1. vcl 4.0;
  2.  
  3. /**
  4.  * Core VCL for Authcache Varnish / Authcache ESI
  5.  * ==============================================
  6.  *
  7.  * WARNING: Do not modify this file but instead start with example.vcl and
  8.  * include the core.vcl from there.
  9.  *
  10.  * By default, the Varnish Cache is bypassed whenever there is a Cookie-Header
  11.  * present on the request. This is a reasonable default behavior because the
  12.  * rationale behind HTTP cookies is essentially to enable personalization of
  13.  * web applications. The results would be disastrous if personalized pages
  14.  * would be cached and delivered regardless of the contents of the Cookie
  15.  * header. For example on an E-commerce site users could end up seeing each
  16.  * others shopping cart, only to name a rather harmless case.
  17.  *
  18.  * This VCL together with Drupal, Authcache Varnish and Authcache ESI allows
  19.  * Varnish to cache personalized content in a safe way without risking the
  20.  * side-effects mentioned above.
  21.  *
  22.  *
  23.  * 1. Backend sets "Vary: X-Authcache-Key" header
  24.  * ----------------------------------------------
  25.  * When the Drupal core option "Cache pages for anonymous users" is enabled, a
  26.  * "Vary: Cookie" header is added to each response from the site. This
  27.  * essentially mandates an intermediate cache server (and also the browser
  28.  * cache) to only deliver a cached version of the page when the Cookie header
  29.  * on a subsequent request is identical to the one of the original request,
  30.  * when the page was first stored in the cache. However it is rather
  31.  * inefficient to store every page for every user separately in a caching
  32.  * server.
  33.  *
  34.  * Because of this, a Drupal site with the Authcache Varnish module enabled
  35.  * will send a "Vary: X-Authcache-Key" header instead of "Vary: Cookie". The
  36.  * caching server now will compare X-Authcache-Key request headers when
  37.  * determining whether a cached version of a page can be sent to the client.
  38.  * However because no browser is sending an X-Authcache-Key header along with a
  39.  * HTTP request, it is necessary to add this header from within the VCL before
  40.  * looking up the object in the cache.
  41.  *
  42.  *
  43.  * 2. Retrieve X-Authcache-Key form the backend and add it onto the request
  44.  * ------------------------------------------------------------------------
  45.  * The authcache key is a value which is unique for every combination of Drupal
  46.  * user roles. The keys of two users are only equal if both of them have the
  47.  * exact same combination of user roles and therefore identical permissions.
  48.  *
  49.  * Authcache Varnish exposes the callback /authcache-varnish-get-key which
  50.  * returns the authcache key for the currently logged in user. Except when one
  51.  * of the roles is excluded from caching, in that case no key is returned from
  52.  * the callback.
  53.  *
  54.  * When a client requests the page /original-url, effectively two requests will
  55.  * be issued by this VCL:
  56.  *   1. GET /authcache-varnish-get-key
  57.  *       -> add resulting X-Authcache-Key to the request and restart.
  58.  *   2. GET /original-url
  59.  *       -> deliver result to client
  60.  * Unfortunately the VCL implementation of this logic is somewhat complicated.
  61.  * Code sections for the key-retrieval are spread over vcl_recv,
  62.  * vcl_backend_response and vcl_deliver.
  63.  *
  64.  *
  65.  * 3. Embed personalized fragments using ESI
  66.  * -----------------------------------------
  67.  * The process described in the preceding section only helps with improving
  68.  * cache efficiency but not with personalization. A site configured like this
  69.  * still is prone to information leakage (e.g. Eve seeing the shopping cart of
  70.  * Alice). In order to solve this problem, personalized items on a page (like a
  71.  * shopping cart block) need to be identified and substituted with ESI tags.
  72.  * Authcache provides a set of modules out of the box helping with substituting
  73.  * personalized content (e.g. Blocks, Views, Form Tokens, Menu Tabs and Action
  74.  * Links, ...).
  75.  *
  76.  * When Authcache ESI is enabled in Drupal, the HTTP header X-Authcache-Do-ESI
  77.  * is added to every response from the backend whenever an ESI tag was added to
  78.  * the markup. This allows vcl_backend_response to selectively enable ESI
  79.  * processing only when necessary.
  80.  *
  81.  * Also Drupal/Authcache ESI will only emit ESI tags, if the X-Authcache-Do-ESI
  82.  * header is on the request to the backend. This header is added from within
  83.  * vcl_recv. As a consequence the backend will not emit ESI tags when caching
  84.  * is bypassed, e.g. due to an earlier "return (pass)" in vcl_recv.
  85.  *
  86.  *
  87.  * Credits & Sources
  88.  * -----------------
  89.  * * Josh Waihi - Authenticated page caching with Varnish & Drupal:
  90.  *   http://joshwaihi.com/content/authenticated-page-caching-varnish-drupal
  91.  * * Four Kitchens - Configure Varnish 3 for Drupal 7:
  92.  *   https://fourkitchens.atlassian.net/wiki/display/TECH/Configure+Varnish+3+for+Drupal+7
  93.  * * The Varnish Book:
  94.  *   https://www.varnish-software.com/static/book/
  95.  * * The Varnish Book - VCL Request Flow:
  96.  *   https://www.varnish-software.com/static/book/_images/vcl.png
  97.  */
  98.  
  99. sub vcl_recv {
  100.     # Add a unique header containing the client address
  101.     unset req.http.X-Forwarded-For;
  102.     set req.http.X-Forwarded-For = client.ip;
  103.  
  104.     if (req.http.host == "xxx.xxx.com") {
  105.         set req.backend_hint = stage;
  106.  
  107.     }
  108.     else {
  109.         set req.backend_hint = default;
  110.     }
  111.  
  112.     if (req.method == "PURGE") {
  113.         if (req.url ~ "hardpurge="){
  114.            // Standar varnish purge
  115.            set req.url = regsuball( req.url, "(^.*)([\?|&]hardpurge=)$", "\1");
  116.            return (purge);
  117.         }
  118.         // Softpurge
  119.         return (hash);
  120.     }
  121.     if (req.method == "BAN") {
  122.         // Ban lurker
  123.         ban("obj.http.url ~ " + regsuball(req.url, "^\/(.*)", "\1")); # Assumes req.url is string contains
  124.         return (synth(200, "Ban added"));
  125.     }
  126.  
  127.     //fix search url with / OR %2F in search word
  128.     if (req.url ~ "^/search/") {
  129.         set req.http.tmp_search = regsuball(req.url, "^.*?\/search\/(.*)", "\1"); //get word
  130.         set req.http.tmp_search = regsuball(req.http.tmp_search, "\/", "%20"); //clean / with white space encoded
  131.         set req.http.tmp_search = regsuball(req.http.tmp_search, "%2F", "%20"); //clean %2F with with white space encoded
  132.         set req.url = regsuball(req.url, "(^.*?\/search\/).*", "\1") + req.http.tmp_search;
  133.         unset req.http.tmp_search;
  134.      }
  135.  
  136.   /**
  137.    * Do not allow the client to pass in X-Authcache-Get-Key header unless the
  138.    * VCL is under test (varnishtest uses -n /tmp/vtc.XXXXX.YYYYYYYY).
  139.    */
  140.   if (req.restarts == 0 && server.identity !~ "^/tmp/vtc.") {
  141.     unset req.http.X-Authcache-Do-ESI;
  142.     unset req.http.X-Authcache-Get-Key;
  143.     unset req.http.X-Authcache-Key-CID;
  144.     unset req.http.X-Authcache-Key;
  145.   }
  146.  
  147.   /**
  148.    * Request was restarted from vcl_deliver after the authcache key was
  149.    * obtained from the backend.
  150.    */
  151.   if (req.restarts > 0 && req.http.X-Authcache-Get-Key == "received") {
  152.     // Restore the original URL.
  153.     set req.url = req.http.X-Original-URL;
  154.     unset req.http.X-Original-URL;
  155.  
  156.     // Remove cache id header.
  157.     unset req.http.X-Authcache-Key-CID;
  158.  
  159.     // Key retrieval is over now
  160.     set req.http.X-Authcache-Get-Key = "done";
  161.  
  162.     // If the backend delivered a key, we proceed with a lookup, otherwise the
  163.     // cache needs to be bypassed.
  164.     if (req.http.X-Authcache-Key) {
  165.       return (hash);
  166.     }
  167.     else {
  168.       return (pass);
  169.     }
  170.   }
  171.  
  172.   /**
  173.    * BEGIN builtin.vcl
  174.    */
  175.   if (req.method == "PRI") {
  176.     /* We do not support SPDY or HTTP/2.0 */
  177.     return (synth(405));
  178.   }
  179.  
  180.   /**
  181.    * EDIT for authcache: In order to allow a site to configure PURGE and inject
  182.    * additional vcl_recv code, branch to a custom function defined in
  183.    * example.vcl here.
  184.    */
  185.   call authcache_recv;
  186.  
  187.  
  188.   # Handle compression correctly. Different browsers send different
  189.   # "Accept-Encoding" headers, even though they mostly all support the same
  190.   # compression mechanisms. By consolidating these compression headers into
  191.   # a consistent format, we can reduce the size of the cache and get more hits.=
  192.   # @see: http:// varnish.projects.linpro.no/wiki/FAQ/Compression
  193.   if (req.http.Accept-Encoding) {
  194.     if (req.http.Accept-Encoding ~ "gzip") {
  195.       # If the browser supports it, we'll use gzip.
  196.       set req.http.Accept-Encoding = "gzip";
  197.     }
  198.     else if (req.http.Accept-Encoding ~ "deflate") {
  199.       # Next, try deflate if it is supported.
  200.       set req.http.Accept-Encoding = "deflate";
  201.     }
  202.     else {
  203.       # Unknown algorithm. Remove it and send unencoded.
  204.       unset req.http.Accept-Encoding;
  205.     }
  206.   }
  207.  
  208.   if (req.method != "GET" &&
  209.     req.method != "HEAD" &&
  210.     req.method != "PUT" &&
  211.     req.method != "POST" &&
  212.     req.method != "TRACE" &&
  213.     req.method != "OPTIONS" &&
  214.     req.method != "DELETE") {
  215.       /* Non-RFC2616 or CONNECT which is weird. */
  216.       return (pipe);
  217.   }
  218.  
  219.   if (req.method != "GET" && req.method != "HEAD") {
  220.       /* We only deal with GET and HEAD by default */
  221.       return (pass);
  222.   }
  223.  
  224.   /**
  225.    * EDIT for authcache: We *need* to allow caching for clients having certain
  226.    * cookies on their request.
  227.    */
  228.   if (req.http.Authorization /* || req.http.Cookie */) {
  229.     /* Not cacheable by default */
  230.     return (pass);
  231.   }
  232.   /* END builtin.vcl */
  233.  
  234.   if (req.restarts == 0) {
  235.     /**
  236.      * Before fulfilling a request, the authcache-key needs to be retrieved
  237.      * either from the cache or the backend.
  238.      *
  239.      * If the variable X-Authcache-Get-Key is set to "get", the request will
  240.      * enter key-retrieval phase before the requested page is delivered. If
  241.      * it is set to "skip", key-retrieval is not attempted.
  242.      *
  243.      * If the users VCL above did not specify whether key retrieval should be
  244.      * performed or not, the default behavior is to skip it as long as there is
  245.      * no session on the request.
  246.      */
  247.     if (!req.http.X-Authcache-Get-Key && req.http.Cookie ~ "(^|;)\s*S?SESS[a-z0-9]+=") {
  248.       set req.http.X-Authcache-Get-Key = "get";
  249.     }
  250.  
  251.     if (req.http.X-Authcache-Get-Key != "get") {
  252.       set req.http.X-Authcache-Get-Key = "skip";
  253.     }
  254.   }
  255.  
  256.   // Skip cache if there are cookies on the request and key-retrieval is
  257.   // disabled.
  258.   if (req.http.X-Authcache-Get-Key == "skip" && req.http.Cookie) {
  259.     return (pass);
  260.   }
  261.  
  262.   // Skip cache when key-retrieval is enabled but nocache-cookie is on the
  263.   // request.
  264.   if (req.http.X-Authcache-Get-Key && req.http.X-Authcache-Get-Key != "skip" && req.http.Cookie ~ "(^|;)\s*nocache=1\s*($|;)") {
  265.     return (pass);
  266.   }
  267.  
  268.   // Retrieve the authcache-key from /authcache-varnish-get-key before each
  269.   // request. Upon vcl_deliver the authcacke-key is copied over to the
  270.   // X-Authcache-Key request header and the request is restarted.
  271.   if (req.http.X-Authcache-Get-Key == "get") {
  272.     call authcache_key_cid;
  273.     call authcache_key_path;
  274.     set req.http.X-Original-URL = req.url;
  275.     set req.url = req.http.X-Authcache-Key-Path;
  276.     set req.http.X-Authcache-Get-Key = "sent";
  277.     unset req.http.X-Authcache-Key-Path;
  278.   }
  279.  
  280.   // Tell the backend that ESI processing is available. The Authcache ESI
  281.   // module will only emit tags if this header is present on the request.
  282.   // If the X-Authcache key is already present on an incoming request (e.g.
  283.   // triggered by Authcache Ajax), do not enable ESI.
  284.   if (req.http.X-Authcache-Get-Key != "skip" && !req.http.X-Authcache) {
  285.     set req.http.X-Authcache-Do-ESI = 1;
  286.   }
  287.  
  288.  
  289.   if (req.http.X-Authcache-Do-ESI && req.esi_level > 0) {
  290.     set req.http.X-Authcache = 1;
  291.   }
  292.  
  293.   return (hash);
  294. }
  295.  
  296. sub vcl_hash {
  297.     //Cache pages with ? get params without them, but NEVER cache authcache.php!! or esi tags url
  298.     if (req.url ~ "^\/search\/") {  //same hash for all search url
  299.         variable.set_string("search_word", regsuball(req.url, "^\/search\/([^?]*).*", "\1"));
  300.         hash_data(regsuball(req.url, "(^.*?\/search\/).*", "\1"));
  301.     } else if (req.url ~ "\?" && req.url !~ "authcache" && req.url !~ "cache.php" ){
  302.         //Not allow get params on url duplicated url with them need more cache
  303.         //Not allow url ending with / duplicated url without it need more cache
  304.         //hash_data(regsuball(regsuball(req.url, "([^?#]*)(\?[^#]*)?", "\1"), "\/$", "")); fail when home /? different cache
  305.         hash_data(regsuball(req.url, "([^?#]*)(\?[^#]*)?", "\1"));
  306.     }  else {
  307.         hash_data(req.url);
  308.     }
  309.  
  310.     if (req.http.host) {
  311.         hash_data(req.http.host);
  312.     } else {
  313.         hash_data(server.ip);
  314.     }
  315.     return (lookup);
  316. }
  317.  
  318. sub vcl_hit {
  319.     if (req.method == "PURGE") {
  320.         softpurge.softpurge();
  321.         return (synth(200, "Successful softpurge"));
  322.     }
  323.    if (obj.ttl >= 0s) {
  324.        // A pure unadultered hit, deliver it
  325.        return (deliver);
  326.    }
  327.    if (obj.ttl + obj.grace > 0s) {
  328.        // Object is in grace, deliver it
  329.        // Automatically triggers a background fetch
  330.        return (deliver);
  331.    }
  332.    // fetch & deliver once we get the result
  333.    return (fetch);
  334. }
  335.  
  336. sub vcl_miss {
  337.     if (req.method == "PURGE") {
  338.         softpurge.softpurge();
  339.         return (synth(200, "Successful softpurge"));
  340.     }
  341. }
  342.  
  343. sub vcl_backend_response {
  344.     set beresp.http.url = bereq.url;//ban lurker
  345.     if (bereq.url ~ "authcache.php" && bereq.http.X-Requested-With != "XMLHttpRequest"){
  346.         unset beresp.http.Cookie;
  347.         unset beresp.http.Set-Cookie;
  348.     }
  349.   //serving expirend content put max value setted on recv
  350.   set beresp.grace = 1440m;//one day
  351.   // Store result of key retrieval for 10 minutes. Do this regardless of
  352.   // whether the request was successful or not. E.g. when the Authcache Varnish
  353.   // module is disabled in the backend (no matter whether on purpose or not),
  354.   // it is still desirable to cache the resulting 404.
  355.   if (bereq.http.X-Authcache-Get-Key == "sent") {
  356.     // If backend did not specify a max-age, assume 10 minutes.
  357.     if (beresp.ttl <= 0 s) {
  358.       set beresp.ttl = 10 m;
  359.     }
  360.  
  361.     // Ensure that we vary on X-Authcache-Key-CID
  362.     if (beresp.http.Vary !~ "X-Authcache-Key-CID") {
  363.         set beresp.http.Vary = beresp.http.Vary + ", X-Authcache-Key-CID";
  364.         set beresp.http.Vary = regsub(beresp.http.Vary, "^,\s*", "");
  365.     }
  366.  
  367.     return (deliver);
  368.   }
  369.  
  370.   // Turn on ESI processing when requested by backend
  371.   if (beresp.http.X-Authcache-Do-ESI) {
  372.     set beresp.do_esi = true;
  373.   }
  374.  
  375.   // Ensure that the result is cached individually for each session if
  376.   // Cache-Control header on the response of an Authcache ESI request
  377.   // contains the "private" keyword.
  378.  
  379.   if (bereq.http.X-Authcache-Do-ESI && bereq.http.X-Authcache){
  380.     if (beresp.http.Cache-Control ~ "(private)" && beresp.http.Vary !~ "Cookie") {
  381.       set beresp.http.Vary = beresp.http.Vary + ", Cookie";
  382.       set beresp.http.Vary = regsub(beresp.http.Vary, "^,\s*", "");
  383.       // Remove the private directive from the Cache-Control response header
  384.       // such that the fragment gets stored by Varnish 4.
  385.       set beresp.http.Cache-Control = regsub(beresp.http.Cache-Control, "(^|,\s*)private", "");
  386.       set beresp.http.Cache-Control = regsub(beresp.http.Cache-Control, "^,\s*", "");
  387.     }
  388.     elseif (beresp.http.Cache-Control ~ "(public)" && beresp.http.Vary !~ "X-Authcache-Key") {
  389.       set beresp.http.Vary = beresp.http.Vary + ", X-Authcache-Key";
  390.       set beresp.http.Vary = regsub(beresp.http.Vary, "^,\s*", "");
  391.     }
  392.   }
  393.   //Remove Cache-Control header for html files, put 3600 seconds on these files, for browser cache
  394.   if (bereq.url ~ "(?i)\.(woff|pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
  395.     set beresp.http.Cache-Control = "public, max-age=1209600"; //cache 2 weeks on browser cache
  396.   } else {
  397.     set beresp.http.Cache-Info = beresp.http.Cache-Control;
  398.     unset beresp.http.Cache-Control;
  399.   }
  400.   if (bereq.url ~ "(?i)\.(woff|png|gif|jpeg|jpg|ico)(\?.*)?$") {
  401.     set beresp.http.Vary = "Accept-Encoding";
  402.     set beresp.ttl = 1209600 s; //cache 2 weeks on varnish
  403.   }
  404.   //global esi urls, same content for all users & roles
  405.   if (bereq.url ~ "node-being-viewed-producto-entrega"
  406.     || bereq.url ~ "frag/panels/home-recommendations-tabs"
  407.     || bereq.url ~ "frag/panels/view-product-list-product-recommendations"
  408.     || bereq.url ~ "frag/panels/view-product-list-product-recommendations-product-type") {
  409.     set beresp.http.Vary = "Accept-Encoding";
  410.   }
  411.  
  412.    if (bereq.url ~ "(?i)\.(css|js)(\?.*)?$") { //save these files one day in varnish
  413.     set beresp.ttl = 86400 s;
  414.   }
  415. }
  416.  
  417. sub vcl_deliver {
  418.     unset resp.http.url; # Optional ban lurker
  419.   if (resp.status == 500) {
  420.     return (synth(resp.status, "Response"));
  421.   }
  422.  
  423.   // Process response from authcache-key callback
  424.   if (req.http.X-Authcache-Get-Key == "sent") {
  425.     // Copy over the X-Authcache-Key header if set
  426.     if (resp.http.X-Authcache-Key) {
  427.       set req.http.X-Authcache-Key = resp.http.X-Authcache-Key;
  428.     }
  429.     // Proceed to next state
  430.     set req.http.X-Authcache-Get-Key = "received";
  431.     return (restart);
  432.   }
  433.  
  434.   // When sending a response from an authcache enabled backend to the browser:
  435.   if (resp.http.Vary ~ "X-Authcache-Key") {
  436.     // 1. Ensure that a Vary: Cookie is on the response
  437.     if (resp.http.Vary !~ "Cookie") {
  438.       set resp.http.Vary = resp.http.Vary + ", Cookie";
  439.     }
  440.     // 2. Remove all X-Authcache-* directives from the Vary header.
  441.     set resp.http.Vary = regsuball(resp.http.Vary, "(^|,\s*)X-Authcache[-a-zA-Z]*", "");
  442.     // 3. Remove a "," prefix, if present.
  443.     set resp.http.Vary = regsub(resp.http.Vary, "^,\s*", "");
  444.   }
  445.  
  446.   // When checking whether it is possible to send a 304 instead of a full 200
  447.   // response, Varnish does not respect the cache-characteristics of embedded
  448.   // ESI fragments. In order to make this work it would be necessary to merge
  449.   // all Last-Modified and ETag response headers of all ESI fragments and
  450.   // generate a new value which is then delivered to the browser. Better 304
  451.   // support has been on the ESI wishlist for some time but it did not happen
  452.   // until now.
  453.   // @see https://www.varnish-cache.org/trac/wiki/Future_ESI
  454.   //
  455.   // Disable HTTP revalidation when a page contains ESI fragments.
  456.   if (resp.http.X-Authcache-Do-ESI) {
  457.     unset resp.http.ETag;
  458.     unset resp.http.Last-Modified;
  459.   }
  460.  
  461.   // Remove variables placed on backend response.
  462.   unset resp.http.X-Authcache-Do-ESI;
  463.   unset resp.http.X-Authcache-Key-CID;
  464.   unset resp.http.X-Authcache-Key;
  465. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement