]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/refresh.cc
renamed refresh_t to RefreshPattern and moved to own header file.
[thirdparty/squid.git] / src / refresh.cc
index 2fd40fba2551ba7ce638d4d1fa03ab61bd5671ce..be36c73de334412bbd94070bebf78a128888a93a 100644 (file)
@@ -1,7 +1,5 @@
 
 /*
- * $Id: refresh.cc,v 1.76 2007/05/24 01:45:03 hno Exp $
- *
  * DEBUG: section 22    Refresh Calculation
  * AUTHOR: Harvest Derived
  *
 #endif
 
 #include "squid.h"
-#include "CacheManager.h"
-#include "Store.h"
-#include "MemObject.h"
+#include "mgr/Registration.h"
+#include "HttpHdrCc.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
+#include "MemObject.h"
+#include "RefreshPattern.h"
 #include "SquidTime.h"
+#include "SquidConfig.h"
+#include "Store.h"
+#include "URL.h"
 
 typedef enum {
     rcHTTP,
@@ -86,6 +88,7 @@ enum {
     STALE_EXPIRES,
     STALE_MAX_RULE,
     STALE_LMFACTOR_RULE,
+    STALE_MAX_STALE,
     STALE_DEFAULT = 299
 };
 
@@ -107,16 +110,16 @@ refreshCounts[rcCount];
 #define REFRESH_DEFAULT_PCT    0.20
 #define REFRESH_DEFAULT_MAX    (time_t)259200
 
-static const refresh_t *refreshUncompiledPattern(const char *);
+static const RefreshPattern *refreshUncompiledPattern(const char *);
 static OBJH refreshStats;
-static int refreshStaleness(const StoreEntry *, time_t, time_t, const refresh_t *, stale_flags *);
+static int refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age, const RefreshPattern * R, stale_flags * sf);
 
-static refresh_t DefaultRefresh;
+static RefreshPattern DefaultRefresh;
 
-const refresh_t *
+const RefreshPattern *
 refreshLimits(const char *url)
 {
-    const refresh_t *R;
+    const RefreshPattern *R;
 
     for (R = Config.Refresh; R; R = R->next) {
         if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
@@ -126,10 +129,10 @@ refreshLimits(const char *url)
     return NULL;
 }
 
-static const refresh_t *
+static const RefreshPattern *
 refreshUncompiledPattern(const char *pat)
 {
-    const refresh_t *R;
+    const RefreshPattern *R;
 
     for (R = Config.Refresh; R; R = R->next) {
         if (0 == strcmp(R->pattern, pat))
@@ -139,14 +142,15 @@ refreshUncompiledPattern(const char *pat)
     return NULL;
 }
 
-/*
+/**
  * Calculate how stale the response is (or will be at the check_time).
  * Staleness calculation is based on the following: (1) response
  * expiration time, (2) age greater than configured maximum, (3)
  * last-modified factor, and (4) age less than configured minimum.
  *
- * If the response is fresh, return -1.  Otherwise return its
- * staleness.  NOTE return value of 0 means the response is stale.
+ * \retval -1  If the response is fresh.
+ * \retval >0  Otherwise return it's staleness.
+ * \retval 0   NOTE return value of 0 means the response is stale.
  *
  * The 'stale_flags' structure is used to tell the calling function
  * _why_ this response is fresh or stale.  Its used, for example,
@@ -154,12 +158,11 @@ refreshUncompiledPattern(const char *pat)
  * times.
  */
 static int
-refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const refresh_t * R, stale_flags * sf)
+refreshStaleness(const StoreEntry * entry, time_t check_time, const time_t age, const RefreshPattern * R, stale_flags * sf)
 {
-    /*
-     * Check for an explicit expiration time.
+    /** \par
+     * Check for an explicit expiration time (Expires: header).
      */
-
     if (entry->expires > -1) {
         sf->expires = true;
 
@@ -176,20 +179,18 @@ refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const
         }
     }
 
-    assert(age >= 0);
-    /*
+    /** \par
      * Use local heuristics to determine staleness.  Start with the
      * max age from the refresh_pattern rule.
      */
-
     if (age > R->max) {
         debugs(22, 3, "STALE: age " << age << " > max " << R->max << " ");
         sf->max = true;
         return (age - R->max);
     }
 
-    /*
-     * Try the last-modified factor algorithm.
+    /** \par
+     * Try the last-modified factor algorithm:  refresh_pattern n% percentage of Last-Modified: age.
      */
     if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
         /*
@@ -208,8 +209,8 @@ refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const
         }
     }
 
-    /*
-     * If we are here, staleness is determined by the refresh_pattern
+    /** \par
+     * Finally, if all else fails;  staleness is determined by the refresh_pattern
      * configured minimum age.
      */
     if (age < R->min) {
@@ -222,15 +223,16 @@ refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const
     return (age - R->min);
 }
 
-/*  return 1 if the entry must be revalidated within delta seconds
- *         0 otherwise
+/**
+ * \retval 1 if the entry must be revalidated within delta seconds
+ * \retval 0 otherwise
  *
  *  note: request maybe null (e.g. for cache digests build)
  */
 static int
 refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
 {
-    const refresh_t *R;
+    const RefreshPattern *R;
     const char *uri = NULL;
     time_t age = 0;
     time_t check_time = squid_curtime + delta;
@@ -247,35 +249,66 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
     if (check_time > entry->timestamp)
         age = check_time - entry->timestamp;
 
+    // FIXME: what to do when age < 0 or counter overflow?
+    assert(age >= 0);
+
     R = uri ? refreshLimits(uri) : refreshUncompiledPattern(".");
 
     if (NULL == R)
         R = &DefaultRefresh;
 
-    memset(&sf, '\0', sizeof(sf));
-
-    staleness = refreshStaleness(entry, check_time, age, R, &sf);
-
-    debugs(22, 3, "Staleness = " << staleness);
-
     debugs(22, 3, "refreshCheck: Matched '" << R->pattern << " " <<
            (int) R->min << " " << (int) (100.0 * R->pct) << "%% " <<
            (int) R->max << "'");
 
-
-    debugs(22, 3, "refreshCheck: age = " << age);
+    debugs(22, 3, "\tage:\t" << age);
 
     debugs(22, 3, "\tcheck_time:\t" << mkrfc1123(check_time));
 
     debugs(22, 3, "\tentry->timestamp:\t" << mkrfc1123(entry->timestamp));
 
-    if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1) {
+    if (request && !request->flags.ignore_cc) {
+        const HttpHdrCc *const cc = request->cache_control;
+        if (cc && cc->hasMinFresh()) {
+            const int32_t minFresh=cc->minFresh();
+            debugs(22, 3, "\tage + min-fresh:\t" << age << " + " <<
+                   minFresh << " = " << age + minFresh);
+            debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time << " + "
+                   << minFresh << " = " <<
+                   mkrfc1123(check_time + minFresh));
+            age += minFresh;
+            check_time += minFresh;
+        }
+    }
+
+    memset(&sf, '\0', sizeof(sf));
+
+    staleness = refreshStaleness(entry, check_time, age, R, &sf);
+
+    debugs(22, 3, "Staleness = " << staleness);
+
+    // stale-if-error requires any failure be passed thru when its period is over.
+    if (request && entry->mem_obj && entry->mem_obj->getReply() && entry->mem_obj->getReply()->cache_control &&
+            entry->mem_obj->getReply()->cache_control->hasStaleIfError() &&
+            entry->mem_obj->getReply()->cache_control->staleIfError() < staleness) {
+
+        debugs(22, 3, "refreshCheck: stale-if-error period expired.");
+        request->flags.fail_on_validation_err = 1;
+    }
+
+    if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1
+#if USE_HTTP_VIOLATIONS
+            && !R->flags.ignore_must_revalidate
+#endif
+       ) {
         debugs(22, 3, "refreshCheck: YES: Must revalidate stale response");
+        if (request)
+            request->flags.fail_on_validation_err = 1;
         return STALE_MUST_REVALIDATE;
     }
 
     /* request-specific checks */
-    if (request) {
+    if (request && !request->flags.ignore_cc) {
         HttpHdrCc *cc = request->cache_control;
 
         if (request->flags.ims && (R->flags.refresh_ims || Config.onoff.refresh_all_ims)) {
@@ -284,7 +317,7 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
             return STALE_FORCED_RELOAD;
         }
 
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
 
         if (!request->flags.nocache_hack) {
             (void) 0;
@@ -304,32 +337,31 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
 
 #endif
         if (NULL != cc) {
-            if (cc->max_age > -1) {
-#if HTTP_VIOLATIONS
-                if (R->flags.ignore_reload && cc->max_age == 0) {} else
+            if (cc->hasMaxAge()) {
+#if USE_HTTP_VIOLATIONS
+                if (R->flags.ignore_reload && cc->maxAge() == 0) {
+                    debugs(22, 3, "refreshCheck: MAYBE: client-max-age = 0 and ignore-reload");
+                } else
 #endif
                 {
-#if 0
-
-                    if (cc->max_age == 0) {
+                    if (cc->maxAge() == 0) {
                         debugs(22, 3, "refreshCheck: YES: client-max-age = 0");
                         return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
                     }
 
-#endif
-                    if (age > cc->max_age) {
+                    if (age > cc->maxAge()) {
                         debugs(22, 3, "refreshCheck: YES: age > client-max-age");
                         return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
                     }
                 }
             }
 
-            if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness > -1) {
-                if (cc->max_stale < 0) {
+            if (cc->hasMaxStale() && staleness > -1) {
+                if (cc->maxStale()==HttpHdrCc::MAX_STALE_ANY) {
                     /* max-stale directive without a value */
                     debugs(22, 3, "refreshCheck: NO: max-stale wildcard");
                     return FRESH_REQUEST_MAX_STALE_ALL;
-                } else if (staleness < cc->max_stale) {
+                } else if (staleness < cc->maxStale()) {
                     debugs(22, 3, "refreshCheck: NO: staleness < max-stale");
                     return FRESH_REQUEST_MAX_STALE_VALUE;
                 }
@@ -360,9 +392,18 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
     /*
      * At this point the response is stale, unless one of
      * the override options kicks in.
+     * NOTE: max-stale config blocks the overrides.
      */
+    int max_stale = (R->max_stale >= 0 ? R->max_stale : Config.maxStale);
+    if ( max_stale >= 0 && staleness > max_stale) {
+        debugs(22, 3, "refreshCheck: YES: max-stale limit");
+        if (request)
+            request->flags.fail_on_validation_err = 1;
+        return STALE_MAX_STALE;
+    }
+
     if (sf.expires) {
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
 
         if (R->flags.override_expire && age < R->min) {
             debugs(22, 3, "refreshCheck: NO: age < min && override-expire");
@@ -377,7 +418,7 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta)
         return STALE_MAX_RULE;
 
     if (sf.lmfactor) {
-#if HTTP_VIOLATIONS
+#if USE_HTTP_VIOLATIONS
 
         if (R->flags.override_lastmod && age < R->min) {
             debugs(22, 3, "refreshCheck: NO: age < min && override-lastmod");
@@ -403,8 +444,8 @@ refreshIsCachable(const StoreEntry * entry)
      * be refreshed.
      */
     int reason = refreshCheck(entry, NULL, Config.minimum_expiry_time);
-    refreshCounts[rcStore].total++;
-    refreshCounts[rcStore].status[reason]++;
+    ++ refreshCounts[rcStore].total;
+    ++ refreshCounts[rcStore].status[reason];
 
     if (reason < STALE_MUST_REVALIDATE)
         /* Does not need refresh. This is certainly cachable */
@@ -430,6 +471,20 @@ refreshIsCachable(const StoreEntry * entry)
     return 1;
 }
 
+/// whether reply is stale if it is a hit
+static bool
+refreshIsStaleIfHit(const int reason)
+{
+    switch (reason) {
+    case FRESH_MIN_RULE:
+    case FRESH_LMFACTOR_RULE:
+    case FRESH_EXPIRES:
+        return false;
+    default:
+        return true;
+    }
+}
+
 /* refreshCheck... functions below are protocol-specific wrappers around
  * refreshCheck() function above */
 
@@ -437,17 +492,18 @@ int
 refreshCheckHTTP(const StoreEntry * entry, HttpRequest * request)
 {
     int reason = refreshCheck(entry, request, 0);
-    refreshCounts[rcHTTP].total++;
-    refreshCounts[rcHTTP].status[reason]++;
-    return (reason < 200) ? 0 : 1;
+    ++ refreshCounts[rcHTTP].total;
+    ++ refreshCounts[rcHTTP].status[reason];
+    request->flags.stale_if_hit = refreshIsStaleIfHit(reason);
+    return (Config.onoff.offline || reason < 200) ? 0 : 1;
 }
 
 int
 refreshCheckICP(const StoreEntry * entry, HttpRequest * request)
 {
     int reason = refreshCheck(entry, request, 30);
-    refreshCounts[rcICP].total++;
-    refreshCounts[rcICP].status[reason]++;
+    ++ refreshCounts[rcICP].total;
+    ++ refreshCounts[rcICP].status[reason];
     return (reason < 200) ? 0 : 1;
 }
 
@@ -456,8 +512,8 @@ int
 refreshCheckHTCP(const StoreEntry * entry, HttpRequest * request)
 {
     int reason = refreshCheck(entry, request, 10);
-    refreshCounts[rcHTCP].total++;
-    refreshCounts[rcHTCP].status[reason]++;
+    ++ refreshCounts[rcHTCP].total;
+    ++ refreshCounts[rcHTCP].status[reason];
     return (reason < 200) ? 0 : 1;
 }
 
@@ -470,8 +526,8 @@ refreshCheckDigest(const StoreEntry * entry, time_t delta)
     int reason = refreshCheck(entry,
                               entry->mem_obj ? entry->mem_obj->request : NULL,
                               delta);
-    refreshCounts[rcCDigest].total++;
-    refreshCounts[rcCDigest].status[reason]++;
+    ++ refreshCounts[rcCDigest].total;
+    ++ refreshCounts[rcCDigest].status[reason];
     return (reason < 200) ? 0 : 1;
 }
 
@@ -480,7 +536,7 @@ refreshCheckDigest(const StoreEntry * entry, time_t delta)
 time_t
 getMaxAge(const char *url)
 {
-    const refresh_t *R;
+    const RefreshPattern *R;
     debugs(22, 3, "getMaxAge: '" << url << "'");
 
     if ((R = refreshLimits(url)))
@@ -575,8 +631,7 @@ refreshStats(StoreEntry * sentry)
 static void
 refreshRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
+    Mgr::RegisterAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
 }
 
 void