]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Added send_hit and store_miss squid.conf directives
authorAlex Rousskov <rousskov@measurement-factory.com>
Wed, 18 Dec 2013 17:19:00 +0000 (10:19 -0700)
committerAlex Rousskov <rousskov@measurement-factory.com>
Wed, 18 Dec 2013 17:19:00 +0000 (10:19 -0700)
to control caching of responses using response info.

The existing "cache" directive is checked before Squid has access to the
response and, hence, could not use response-based ACLs such as http_status.
Response-based ACLs may be essential when fine-tuning caching. Squid Bug 3937
(StoreID can lead to 302 infinite loop) is a good use case.

Updated old "cache" directive documentation to provide more information, to
help folks distinguish the three related directives, and to polish for
clarity.

TODO: Support lookup_hit and possibly deprecate/remove "cache".

src/Server.cc
src/Server.h
src/SquidConfig.h
src/cf.data.pre
src/client_side_reply.cc
src/client_side_reply.h

index 9c7fe1e6a01cecee41f599fc7e6c9213719c4e35..3a9b2b4c5eb4588d911cfa3183cd112307e4331d 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include "squid.h"
+#include "acl/FilledChecklist.h"
 #include "acl/Gadgets.h"
 #include "base/TextException.h"
 #include "comm/Connection.h"
@@ -174,6 +175,8 @@ ServerStateData::setFinalReply(HttpReply *rep)
     // give entry the reply because haveParsedReplyHeaders() expects it there
     entry->replaceHttpReply(theFinalReply, false); // but do not write yet
     haveParsedReplyHeaders(); // update the entry/reply (e.g., set timestamps)
+    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE) && blockCaching())
+        entry->release();
     entry->startWriting(); // write the updated entry to store
 
     return theFinalReply;
@@ -533,6 +536,24 @@ ServerStateData::haveParsedReplyHeaders()
     currentOffset = partial ? theFinalReply->content_range->spec.offset : 0;
 }
 
+/// whether to prevent caching of an otherwise cachable response
+bool
+ServerStateData::blockCaching()
+{
+    if (const Acl::Tree *acl = Config.accessList.storeMiss) {
+        // This relatively expensive check is not in StoreEntry::checkCachable:
+        // That method lacks HttpRequest and may be called too many times.
+        ACLFilledChecklist ch(acl, originalRequest(), NULL);
+        ch.reply = const_cast<HttpReply*>(entry->getReply()); // ACLFilledChecklist API bug
+        HTTPMSGLOCK(ch.reply);
+        if (ch.fastCheck() != ACCESS_ALLOWED) { // when in doubt, block
+            debugs(20, 3, "store_miss prohibits caching");
+            return true;
+        }
+    }
+    return false;
+}
+
 HttpRequest *
 ServerStateData::originalRequest()
 {
index 2633e8f8f317f9cecbab6e93e88f3e3b08376d95..25f9e69d39e6af23dcfb8c696276c4c5a3a36f59 100644 (file)
@@ -131,6 +131,8 @@ protected:
     /// Entry-dependent callbacks use this check to quit if the entry went bad
     bool abortOnBadEntry(const char *abortReason);
 
+    bool blockCaching();
+
 #if USE_ADAPTATION
     void startAdaptation(const Adaptation::ServiceGroupPointer &group, HttpRequest *cause);
     void adaptVirginReplyBody(const char *buf, ssize_t len);
index 35855a908f09893bf7c403721f053cc8c35d060c..8efc16c6c27d4529f5ea4d56a12a0221470af446 100644 (file)
@@ -364,6 +364,8 @@ public:
         acl_access *AlwaysDirect;
         acl_access *ASlists;
         acl_access *noCache;
+        acl_access *sendHit;
+        acl_access *storeMiss;
         acl_access *stats_collection;
 #if SQUID_SNMP
 
index fa84a9cba1e91927cb2f1c11ea33e020d974be58..8293d8c1995d33cc6ea04b0bb4b1a0bddc509d58 100644 (file)
@@ -4851,18 +4851,97 @@ COMMENT_END
 NAME: cache no_cache
 TYPE: acl_access
 DEFAULT: none
-DEFAULT_DOC: Allow caching, unless rules exist in squid.conf.
+DEFAULT_DOC: By default, this directive is unused and has no effect.
 LOC: Config.accessList.noCache
 DOC_START
-       A list of ACL elements which, if matched and denied, cause the request to
-       not be satisfied from the cache and the reply to not be cached.
-       In other words, use this to force certain objects to never be cached.
-
-       You must use the words 'allow' or 'deny' to indicate whether items
-       matching the ACL should be allowed or denied into the cache.
+       Requests denied by this directive will not be served from the cache
+       and their responses will not be stored in the cache. This directive
+       has no effect on other transactions and on already cached responses.
 
        This clause supports both fast and slow acl types.
        See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
+
+       This and the two other similar caching directives listed below are
+       checked at different transaction processing stages, have different
+       access to response information, affect different cache operations,
+       and differ in slow ACLs support:
+
+       * cache: Checked before Squid makes a hit/miss determination.
+               No access to reply information!
+               Denies both serving a hit and storing a miss.
+               Supports both fast and slow ACLs.
+       * send_hit: Checked after a hit was detected.
+               Has access to reply (hit) information.
+               Denies serving a hit only.
+               Supports fast ACLs only.
+       * store_miss: Checked before storing a cachable miss.
+               Has access to reply (miss) information.
+               Denies storing a miss only.
+               Supports fast ACLs only.
+
+       If you are not sure which of the three directives to use, apply the
+       following decision logic:
+
+       * If your ACL(s) are of slow type _and_ need response info, redesign.
+         Squid does not support that particular combination at this time.
+        Otherwise:
+       * If your directive ACL(s) are of slow type, use "cache"; and/or
+       * if your directive ACL(s) need no response info, use "cache".
+        Otherwise:
+       * If you do not want the response cached, use store_miss; and/or
+       * if you do not want a hit on a cached response, use send_hit.
+DOC_END
+
+NAME: send_hit
+TYPE: acl_access
+DEFAULT: none
+DEFAULT_DOC: By default, this directive is unused and has no effect.
+LOC: Config.accessList.sendHit
+DOC_START
+       Responses denied by this directive will not be served from the cache
+       (but may still be cached, see store_miss). This directive has no
+       effect on the responses it allows and on the cached objects.
+
+       Please see the "cache" directive for a summary of differences among
+       store_miss, send_hit, and cache directives.
+
+       Unlike the "cache" directive, send_hit only supports fast acl
+       types.  See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
+
+       For example:
+
+               # apply custom Store ID mapping to some URLs
+               acl MapMe dstdomain .c.example.com
+               store_id_program ...
+               store_id_access allow MapMe
+
+               # but prevent caching of special responses
+               # such as 302 redirects that cause StoreID loops
+               acl Ordinary http_status 200-299
+               store_miss deny MapMe !Ordinary
+
+               # and do not serve any previously stored special responses
+               # from the cache (in case they were already cached before
+               # the above store_miss rule was in effect).
+               send_hit deny MapMe !Ordinary
+DOC_END
+
+NAME: store_miss
+TYPE: acl_access
+DEFAULT: none
+DEFAULT_DOC: By default, this directive is unused and has no effect.
+LOC: Config.accessList.storeMiss
+DOC_START
+       Responses denied by this directive will not be cached (but may still
+       be served from the cache, see send_hit). This directive has no
+       effect on the responses it allows and on the already cached responses.
+
+       Please see the "cache" directive for a summary of differences among
+       store_miss, send_hit, and cache directives. See the
+       send_hit directive for a usage example.
+
+       Unlike the "cache" directive, store_miss only supports fast acl
+       types.  See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
 DOC_END
 
 NAME: max_stale
index d8617d3b1bda3afed0fbe257a4248ec3580b8b01..2d55c05479c93197f9630b32702d94bb8810ca13 100644 (file)
@@ -536,6 +536,11 @@ clientReplyContext::cacheHit(StoreIOBuffer result)
        ) {
         http->logType = LOG_TCP_NEGATIVE_HIT;
         sendMoreData(result);
+    } else if (blockedHit()) {
+        debugs(88, 5, "send_hit forces a MISS");
+        http->logType = LOG_TCP_MISS;
+        processMiss();
+        return;
     } else if (!http->flags.internal && refreshCheckHTTP(e, r)) {
         debugs(88, 5, "clientCacheHit: in refreshCheck() block");
         /*
@@ -764,6 +769,30 @@ clientReplyContext::processConditional(StoreIOBuffer &result)
     }
 }
 
+/// whether squid.conf send_hit prevents us from serving this hit
+bool
+clientReplyContext::blockedHit() const
+{
+    if (!Config.accessList.sendHit)
+        return false; // hits are not blocked by default
+
+    if (http->flags.internal)
+        return false; // internal content "hits" cannot be blocked
+
+    if (const HttpReply *rep = http->storeEntry()->getReply()) {
+        std::auto_ptr<ACLFilledChecklist> chl(clientAclChecklistCreate(Config.accessList.sendHit, http));
+        chl->reply = const_cast<HttpReply*>(rep); // ACLChecklist API bug
+        HTTPMSGLOCK(chl->reply);
+        return chl->fastCheck() != ACCESS_ALLOWED; // when in doubt, block
+    }
+
+    // This does not happen, I hope, because we are called from CacheHit, which
+    // is called via a storeClientCopy() callback, and store should initialize
+    // the reply before calling that callback.
+    debugs(88, 3, "Missing reply!");
+    return false;
+}
+
 void
 clientReplyContext::purgeRequestFindObjectToPurge()
 {
index 15a34fe0de9d57236973d19543ba576a0b5691f5..7cebe1cc7bcbc5895cc902e479f9fd72a427a337 100644 (file)
@@ -140,6 +140,7 @@ private:
     void triggerInitialStoreRead();
     void sendClientOldEntry();
     void purgeAllCached();
+    bool blockedHit() const;
 
     void sendBodyTooLargeError();
     void sendPreconditionFailedError();