]> git.ipfire.org Git - thirdparty/squid.git/blob - src/refresh.cc
put http-violating code inside HTTP_VIOLATIONS
[thirdparty/squid.git] / src / refresh.cc
1
2
3 /*
4 * $Id: refresh.cc,v 1.34 1998/08/21 04:03:48 wessels Exp $
5 *
6 * DEBUG: section 22 Refresh Calculation
7 * AUTHOR: Harvest Derived
8 *
9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
10 * ----------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
14 * National Laboratory for Applied Network Research and funded by the
15 * National Science Foundation. Squid is Copyrighted (C) 1998 by
16 * Duane Wessels and the University of California San Diego. Please
17 * see the COPYRIGHT file for full details. Squid incorporates
18 * software developed and/or copyrighted by other sources. Please see
19 * the CREDITS file for full details.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
35 */
36
37 #ifndef USE_POSIX_REGEX
38 #define USE_POSIX_REGEX /* put before includes; always use POSIX */
39 #endif
40
41 #include "squid.h"
42
43 struct {
44 int total;
45 int revalidate_stale;
46 int request_max_age_stale;
47 int response_expires_stale;
48 int response_expires_fresh;
49 int conf_max_age_stale;
50 int last_modified_factor_fresh;
51 int last_modified_factor_stale;
52 int conf_min_age_fresh;
53 int default_stale;
54 } refreshCounts;
55
56 /*
57 * Defaults:
58 * MIN NONE
59 * PCT 20%
60 * MAX 3 days
61 */
62 #define REFRESH_DEFAULT_MIN (time_t)0
63 #define REFRESH_DEFAULT_PCT 0.20
64 #define REFRESH_DEFAULT_MAX (time_t)259200
65
66 static const refresh_t *refreshLimits(const char *);
67 static const refresh_t *refreshUncompiledPattern(const char *);
68 static OBJH refreshStats;
69
70 static const refresh_t *
71 refreshLimits(const char *url)
72 {
73 const refresh_t *R;
74 for (R = Config.Refresh; R; R = R->next) {
75 if (!regexec(&(R->compiled_pattern), url, 0, 0, 0))
76 return R;
77 }
78 return NULL;
79 }
80
81 static const refresh_t *
82 refreshUncompiledPattern(const char *pat)
83 {
84 const refresh_t *R;
85 for (R = Config.Refresh; R; R = R->next) {
86 if (0 == strcmp(R->pattern, pat))
87 return R;
88 }
89 return NULL;
90 }
91
92 /*
93 * refreshCheck():
94 * return 1 if its time to revalidate this entry, 0 otherwise
95 */
96 int
97 refreshCheck(const StoreEntry * entry, request_t * request, time_t delta)
98 {
99 const refresh_t *R;
100 const char *uri;
101 time_t min = REFRESH_DEFAULT_MIN;
102 double pct = REFRESH_DEFAULT_PCT;
103 time_t max = REFRESH_DEFAULT_MAX;
104 #if HTTP_VIOLATIONS
105 int override_expire = 0;
106 int override_lastmod = 0;
107 int reload_into_ims = 0;
108 int ignore_reload = 0;
109 #endif
110 const char *pattern = ".";
111 time_t age;
112 double factor;
113 time_t check_time = squid_curtime + delta;
114 if (entry->mem_obj)
115 uri = entry->mem_obj->url;
116 else
117 uri = urlCanonical(request);
118 debug(22, 3) ("refreshCheck: '%s'\n", uri);
119 refreshCounts.total++;
120 if (EBIT_TEST(entry->flag, ENTRY_REVALIDATE)) {
121 debug(22, 3) ("refreshCheck: YES: Required Authorization\n");
122 refreshCounts.revalidate_stale++;
123 return 1;
124 }
125 if ((R = refreshLimits(uri))) {
126 min = R->min;
127 pct = R->pct;
128 max = R->max;
129 pattern = R->pattern;
130 #if HTTP_VIOLATIONS
131 override_expire = R->flags.override_expire;
132 override_lastmod = R->flags.override_lastmod;
133 reload_into_ims = R->flags.reload_into_ims;
134 ignore_reload = R->flags.ignore_reload;
135 #endif
136 }
137 #if HTTP_VIOLATIONS
138 if (!reload_into_ims)
139 reload_into_ims = Config.onoff.reload_into_ims;
140 #endif
141 debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n",
142 pattern, (int) min, (int) (100.0 * pct), (int) max);
143 age = check_time - entry->timestamp;
144 debug(22, 3) ("refreshCheck: age = %d\n", (int) age);
145 debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time));
146 debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp));
147 #if HTTP_VIOLATIONS
148 if (request->flags.nocache_hack) {
149 if (ignore_reload) {
150 /* The clients no-cache header is ignored */
151 debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n");
152 } else if (reload_into_ims) {
153 /* The clients no-cache header is changed into a IMS query */
154 debug(22, 3) ("refreshCheck: YES: reload-into-ims\n");
155 return 1;
156 } else {
157 /* The clients no-cache header is not overridden on this request */
158 debug(22, 3) ("refreshCheck: YES: client reload\n");
159 request->flags.nocache = 1;
160 return 1;
161 }
162 }
163 #endif
164 if (request->max_age > -1) {
165 if (age > request->max_age) {
166 debug(22, 3) ("refreshCheck: YES: age > client-max-age\n");
167 refreshCounts.request_max_age_stale++;
168 return 1;
169 }
170 }
171 #if HTTP_VIOLATIONS
172 if (override_expire && age <= min) {
173 debug(22, 3) ("refreshCheck: NO: age < min && override_expire\n");
174 return 0;
175 }
176 #endif
177 if (entry->expires > -1) {
178 if (entry->expires <= check_time) {
179 debug(22, 3) ("refreshCheck: YES: expires <= curtime\n");
180 refreshCounts.response_expires_stale++;
181 return 1;
182 } else {
183 debug(22, 3) ("refreshCheck: NO: expires > curtime\n");
184 refreshCounts.response_expires_fresh++;
185 return 0;
186 }
187 }
188 if (age > max) {
189 debug(22, 3) ("refreshCheck: YES: age > max\n");
190 refreshCounts.conf_max_age_stale++;
191 return 1;
192 }
193 #if HTTP_VIOLATIONS
194 if (override_lastmod && age <= min) {
195 debug(22, 3) ("refreshCheck: NO: age < min && override_lastmod\n");
196 return 0;
197 }
198 #endif
199 if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
200 factor = (double) age / (double) (entry->timestamp - entry->lastmod);
201 debug(22, 3) ("refreshCheck: factor = %f\n", factor);
202 if (factor < pct) {
203 debug(22, 3) ("refreshCheck: NO: factor < pct\n");
204 refreshCounts.last_modified_factor_fresh++;
205 return 0;
206 } else {
207 debug(22, 3) ("refreshCheck: YES: factor >= pct\n");
208 refreshCounts.last_modified_factor_stale++;
209 return 1;
210 }
211 }
212 if (age <= min) {
213 debug(22, 3) ("refreshCheck: NO: age < min\n");
214 refreshCounts.conf_min_age_fresh++;
215 return 0;
216 }
217 debug(22, 3) ("refreshCheck: YES: default stale\n");
218 refreshCounts.default_stale++;
219 return 1;
220 }
221
222 /* returns an approximate time when refreshCheck() may return true */
223 time_t
224 refreshWhen(const StoreEntry * entry)
225 {
226 const refresh_t *R;
227 time_t refresh_time = squid_curtime;
228 time_t min = REFRESH_DEFAULT_MIN;
229 time_t max = REFRESH_DEFAULT_MAX;
230 double pct = REFRESH_DEFAULT_PCT;
231 const char *pattern = ".";
232 if (entry->mem_obj) {
233 assert(entry->mem_obj->url);
234 debug(22, 3) ("refreshWhen: key '%s'\n", storeKeyText(entry->key));
235 debug(22, 3) ("refreshWhen: url '%s'\n", entry->mem_obj->url);
236 if (EBIT_TEST(entry->flag, ENTRY_REVALIDATE)) {
237 debug(22, 3) ("refreshWhen: NOW: Required Authorization\n");
238 return refresh_time;
239 }
240 debug(22, 3) ("refreshWhen: entry: exp: %d, tstamp: %d, lmt: %d\n",
241 entry->expires, entry->timestamp, entry->lastmod);
242 R = refreshLimits(entry->mem_obj->url);
243 } else {
244 R = refreshUncompiledPattern(".");
245 }
246 if (R != NULL) {
247 min = R->min;
248 max = R->max;
249 pct = R->pct;
250 pattern = R->pattern;
251 }
252 debug(22, 3) ("refreshWhen: Matched '%s %d %d%% %d'\n",
253 pattern, (int) min, (int) (100.0 * pct), (int) max);
254 /* convert to absolute numbers */
255 min += entry->timestamp;
256 max += entry->timestamp;
257 if (-1 < entry->expires) {
258 debug(22, 3) ("refreshWhen: expires set\n");
259 refresh_time = entry->expires;
260 } else if (entry->timestamp <= entry->lastmod) {
261 debug(22, 3) ("refreshWhen: lastvalid <= lastmod\n");
262 refresh_time = squid_curtime;
263 } else {
264 refresh_time = (entry->timestamp - entry->lastmod) * pct + entry->timestamp;
265 debug(22, 3) ("refreshWhen: using refresh pct\n");
266 }
267 /* take min/max into account, max takes priority over min */
268 if (refresh_time < min)
269 refresh_time = min;
270 if (refresh_time > max)
271 refresh_time = max;
272 debug(22, 3) ("refreshWhen: answer: %d (in %d secs)\n",
273 refresh_time, (int) (refresh_time - squid_curtime));
274 return refresh_time;
275 }
276
277 time_t
278 getMaxAge(const char *url)
279 {
280 const refresh_t *R;
281 debug(22, 3) ("getMaxAge: '%s'\n", url);
282 if ((R = refreshLimits(url)))
283 return R->max;
284 else
285 return REFRESH_DEFAULT_MAX;
286 }
287
288 static void
289 refreshStats(StoreEntry * sentry)
290 {
291 storeAppendPrintf(sentry, "refreshCounts.total\t%d\n",
292 refreshCounts.total);
293 storeAppendPrintf(sentry, "refreshCounts.revalidate_stale\t%d\n",
294 refreshCounts.revalidate_stale);
295 storeAppendPrintf(sentry, "refreshCounts.request_max_age_stale\t%d\n",
296 refreshCounts.request_max_age_stale);
297 storeAppendPrintf(sentry, "refreshCounts.response_expires_stale\t%d\n",
298 refreshCounts.response_expires_stale);
299 storeAppendPrintf(sentry, "refreshCounts.response_expires_fresh\t%d\n",
300 refreshCounts.response_expires_fresh);
301 storeAppendPrintf(sentry, "refreshCounts.conf_max_age_stale\t%d\n",
302 refreshCounts.conf_max_age_stale);
303 storeAppendPrintf(sentry, "refreshCounts.last_modified_factor_fresh\t%d\n",
304 refreshCounts.last_modified_factor_fresh);
305 storeAppendPrintf(sentry, "refreshCounts.last_modified_factor_stale\t%d\n",
306 refreshCounts.last_modified_factor_stale);
307 storeAppendPrintf(sentry, "refreshCounts.conf_min_age_fresh\t%d\n",
308 refreshCounts.conf_min_age_fresh);
309 storeAppendPrintf(sentry, "refreshCounts.default_stale\t%d\n",
310 refreshCounts.default_stale);
311 }
312
313 void
314 refreshInit(void)
315 {
316 cachemgrRegister("refresh",
317 "Refresh Algorithm Statistics",
318 refreshStats,
319 0,
320 1);
321 }