void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type id, time_t htime) { assert_eid(id); assert(Headers[id].type == ftDate_1123); /* must be of an appropriate type */ assert(htime >= 0); httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, mkrfc1123(htime))); }
static void print_trailer(void) { printf("<HR>\n"); printf("<ADDRESS>\n"); printf("Generated %s, by %s/%s@%s\n", mkrfc1123(now), progname, SQUID_VERSION, getfullhostname()); printf("</ADDRESS></BODY></HTML>\n"); }
static void gopherHTMLFooter(StoreEntry * e) { storeAppendPrintf(e, "<HR noshade size=\"1px\">\n"); storeAppendPrintf(e, "<ADDRESS>\n"); storeAppendPrintf(e, "Generated %s by %s (%s)\n", mkrfc1123(squid_curtime), getMyHostname(), visible_appname_string); storeAppendPrintf(e, "</ADDRESS></BODY></HTML>\n"); }
/* create MIME Header for Gopher Data */ static void gopherMimeCreate(GopherStateData * gopherState) { MemBuf mb; memBufDefInit(&mb); memBufPrintf(&mb, "HTTP/1.0 200 OK Gatewaying\r\n" "Server: Squid/%s\r\n" "Date: %s\r\n" "MIME-version: 1.0\r\n", version_string, mkrfc1123(squid_curtime)); switch (gopherState->type_id) { case GOPHER_DIRECTORY: case GOPHER_INDEX: case GOPHER_HTML: case GOPHER_WWW: case GOPHER_CSO: memBufPrintf(&mb, "Content-Type: text/html\r\n"); break; case GOPHER_GIF: case GOPHER_IMAGE: case GOPHER_PLUS_IMAGE: memBufPrintf(&mb, "Content-Type: image/gif\r\n"); break; case GOPHER_SOUND: case GOPHER_PLUS_SOUND: memBufPrintf(&mb, "Content-Type: audio/basic\r\n"); break; case GOPHER_PLUS_MOVIE: memBufPrintf(&mb, "Content-Type: video/mpeg\r\n"); break; case GOPHER_MACBINHEX: case GOPHER_DOSBIN: case GOPHER_UUENCODED: case GOPHER_BIN: /* Rightnow We have no idea what it is. */ gopher_mime_content(&mb, gopherState->request, def_gopher_bin); break; case GOPHER_FILE: default: gopher_mime_content(&mb, gopherState->request, def_gopher_text); break; } memBufPrintf(&mb, "\r\n"); EBIT_CLR(gopherState->entry->flags, ENTRY_FWD_HDR_WAIT); storeAppend(gopherState->entry, mb.buf, mb.size); memBufClean(&mb); }
int main() { char *x; time_t t, pt; t = time(NULL); x = mkrfc1123(t); printf("HTTP Time: %s\n", x); pt = parse_rfc1123(x); printf("Parsed: %d vs. %d\n", pt, t); }
static const char * errorConvert(char token, ErrorState * err) { request_t *r = err->request; static MemBuf mb = MemBufNULL; const char *p = NULL; /* takes priority over mb if set */ int do_quote = 1; memBufReset(&mb); switch (token) { case 'a': if (r && r->auth_user_request) p = authenticateUserRequestUsername(r->auth_user_request); if (!p) p = "-"; break; case 'B': p = r ? ftpUrlWith2f(r) : "[no URL]"; break; case 'c': p = errorPageName(err->type); break; case 'e': memBufPrintf(&mb, "%d", err->xerrno); break; case 'E': if (err->xerrno) memBufPrintf(&mb, "(%d) %s", err->xerrno, strerror(err->xerrno)); else memBufPrintf(&mb, "[No Error]"); break; case 'f': /* FTP REQUEST LINE */ if (err->ftp.request) p = err->ftp.request; else p = "nothing"; break; case 'F': /* FTP REPLY LINE */ if (err->ftp.request) p = err->ftp.reply; else p = "nothing"; break; case 'g': /* FTP SERVER MESSAGE */ wordlistCat(err->ftp.server_msg, &mb); break; case 'h': memBufPrintf(&mb, "%s", getMyHostname()); break; case 'H': if (r) { if (r->hier.host) p = r->hier.host; else p = r->host; } else p = "[unknown host]"; break; case 'i': memBufPrintf(&mb, "%s", inet_ntoa(err->src_addr)); break; case 'I': if (r && r->hier.host) { memBufPrintf(&mb, "%s", r->hier.host); } else p = "[unknown]"; break; case 'L': if (Config.errHtmlText) { memBufPrintf(&mb, "%s", Config.errHtmlText); do_quote = 0; } else p = "[not available]"; break; case 'm': p = authenticateAuthUserRequestMessage(err->auth_user_request) ? authenticateAuthUserRequestMessage(err->auth_user_request) : "[not available]"; break; case 'M': p = r ? RequestMethods[r->method].str : "[unknown method]"; break; case 'o': p = external_acl_message; if (!p) p = "[not available]"; break; case 'p': if (r) { memBufPrintf(&mb, "%d", (int) r->port); } else { p = "[unknown port]"; } break; case 'P': p = r ? ProtocolStr[r->protocol] : "[unkown protocol]"; break; case 'R': if (NULL != r) { Packer p; memBufPrintf(&mb, "%s %s HTTP/%d.%d\n", RequestMethods[r->method].str, strLen(r->urlpath) ? strBuf(r->urlpath) : "/", r->http_ver.major, r->http_ver.minor); packerToMemInit(&p, &mb); httpHeaderPackInto(&r->header, &p); packerClean(&p); } else if (err->request_hdrs) { p = err->request_hdrs; } else { p = "[no request]"; } break; case 's': p = visible_appname_string; break; case 'S': /* signature may contain %-escapes, recursion */ if (err->page_id != ERR_SQUID_SIGNATURE) { const int saved_id = err->page_id; MemBuf sign_mb; err->page_id = ERR_SQUID_SIGNATURE; sign_mb = errorBuildContent(err); memBufPrintf(&mb, "%s", sign_mb.buf); memBufClean(&sign_mb); err->page_id = saved_id; do_quote = 0; } else { /* wow, somebody put %S into ERR_SIGNATURE, stop recursion */ p = "[%S]"; } break; case 't': memBufPrintf(&mb, "%s", mkhttpdlogtime(&squid_curtime)); break; case 'T': memBufPrintf(&mb, "%s", mkrfc1123(squid_curtime)); break; case 'U': p = r ? urlCanonicalClean(r) : err->url ? err->url : "[no URL]"; break; case 'u': p = r ? urlCanonical(r) : err->url ? err->url : "[no URL]"; break; case 'w': if (Config.adminEmail) memBufPrintf(&mb, "%s", Config.adminEmail); else p = "[unknown]"; break; case 'z': if (err->dnsserver_msg) p = err->dnsserver_msg; else p = "[unknown]"; break; case '%': p = "%"; break; default: memBufPrintf(&mb, "%%%c", token); do_quote = 0; break; } if (!p) p = mb.buf; /* do not use mb after this assignment! */ assert(p); debug(4, 3) ("errorConvert: %%%c --> '%s'\n", token, p); if (do_quote) p = html_quote(p); return p; }
int main(int argc, char *argv[]) { int conn, c, len, bytesWritten; int port, to_stdout, reload; int ping, pcount; int keep_alive = 0; int opt_noaccept = 0; int opt_verbose = 0; const char *hostname, *localhost; char url[BUFSIZ], msg[BUFSIZ], buf[BUFSIZ]; char extra_hdrs[BUFSIZ]; const char *method = "GET"; extern char *optarg; time_t ims = 0; int max_forwards = -1; struct timeval tv1, tv2; int i = 0, loops; long ping_int; long ping_min = 0, ping_max = 0, ping_sum = 0, ping_mean = 0; char *proxy_user = NULL; char *proxy_password = NULL; char *www_user = NULL; char *www_password = NULL; /* set the defaults */ hostname = "localhost"; localhost = NULL; extra_hdrs[0] = '\0'; port = CACHE_HTTP_PORT; to_stdout = 1; reload = 0; ping = 0; pcount = 0; ping_int = 1 * 1000; if (argc < 2) { usage(argv[0]); /* need URL */ } else if (argc >= 2) { strncpy(url, argv[argc - 1], BUFSIZ); url[BUFSIZ - 1] = '\0'; if (url[0] == '-') usage(argv[0]); while ((c = getopt(argc, argv, "ah:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1) switch (c) { case 'a': opt_noaccept = 1; break; case 'h': /* remote host */ if (optarg != NULL) hostname = optarg; break; case 'l': /* local host */ if (optarg != NULL) localhost = optarg; break; case 's': /* silent */ to_stdout = 0; break; case 'k': /* backward compat */ keep_alive = 1; break; case 'r': /* reload */ reload = 1; break; case 'p': /* port number */ sscanf(optarg, "%d", &port); if (port < 1) port = CACHE_HTTP_PORT; /* default */ break; case 'P': put_file = xstrdup(optarg); break; case 'i': /* IMS */ ims = (time_t) atoi(optarg); break; case 'm': method = xstrdup(optarg); break; case 't': method = xstrdup("TRACE"); max_forwards = atoi(optarg); break; case 'g': ping = 1; pcount = atoi(optarg); to_stdout = 0; break; case 'I': if ((ping_int = atoi(optarg) * 1000) <= 0) usage(argv[0]); break; case 'H': if (strlen(optarg)) { char *t; strncpy(extra_hdrs, optarg, sizeof(extra_hdrs)); while ((t = strstr(extra_hdrs, "\\n"))) *t = '\r', *(t + 1) = '\n'; } break; case 'T': io_timeout = atoi(optarg); break; case 'u': proxy_user = optarg; break; case 'w': proxy_password = optarg; break; case 'U': www_user = optarg; break; case 'W': www_password = optarg; break; case 'v': /* undocumented: may increase verb-level by giving more -v's */ opt_verbose++; break; case '?': /* usage */ default: usage(argv[0]); break; } } #ifdef _SQUID_MSWIN_ { WSADATA wsaData; WSAStartup(2, &wsaData); } #endif /* Build the HTTP request */ if (strncmp(url, "mgr:", 4) == 0) { char *t = xstrdup(url + 4); snprintf(url, BUFSIZ, "cache_object://%s/%s", hostname, t); xfree(t); } if (put_file) { put_fd = open(put_file, O_RDONLY); set_our_signal(); if (put_fd < 0) { fprintf(stderr, "%s: can't open file (%s)\n", argv[0], xstrerror()); exit(-1); } #ifdef _SQUID_WIN32_ setmode(put_fd, O_BINARY); #endif fstat(put_fd, &sb); } snprintf(msg, BUFSIZ, "%s %s HTTP/1.0\r\n", method, url); if (reload) { snprintf(buf, BUFSIZ, "Pragma: no-cache\r\n"); strcat(msg, buf); } if (put_fd > 0) { snprintf(buf, BUFSIZ, "Content-length: %d\r\n", (int) sb.st_size); strcat(msg, buf); } if (opt_noaccept == 0) { snprintf(buf, BUFSIZ, "Accept: */*\r\n"); strcat(msg, buf); } if (ims) { snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims)); strcat(msg, buf); } if (max_forwards > -1) { snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards); strcat(msg, buf); } if (proxy_user) { char *user = proxy_user; char *password = proxy_password; #if HAVE_GETPASS if (!password) password = getpass("Proxy password: "******"ERROR: Proxy password missing\n"); exit(1); } snprintf(buf, BUFSIZ, "%s:%s", user, password); snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %s\r\n", base64_encode(buf)); strcat(msg, buf); } if (www_user) { char *user = www_user; char *password = www_password; #if HAVE_GETPASS if (!password) password = getpass("WWW password: "******"ERROR: WWW password missing\n"); exit(1); } snprintf(buf, BUFSIZ, "%s:%s", user, password); snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", base64_encode(buf)); strcat(msg, buf); } if (keep_alive) { if (port != 80) snprintf(buf, BUFSIZ, "Proxy-Connection: keep-alive\r\n"); else snprintf(buf, BUFSIZ, "Connection: keep-alive\r\n"); strcat(msg, buf); } strcat(msg, extra_hdrs); snprintf(buf, BUFSIZ, "\r\n"); strcat(msg, buf); if (opt_verbose) fprintf(stderr, "headers: '%s'\n", msg); if (ping) { #if HAVE_SIGACTION struct sigaction sa, osa; if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) { sa.sa_handler = catchSignal; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); (void) sigaction(SIGINT, &sa, NULL); } #else void (*osig) (); if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL) (void) signal(SIGINT, osig); #endif } loops = ping ? pcount : 1; for (i = 0; loops == 0 || i < loops; i++) { squid_off_t fsize = 0; /* Connect to the server */ if ((conn = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("client: socket"); exit(1); } if (localhost && client_comm_bind(conn, localhost) < 0) { perror("client: bind"); exit(1); } if (client_comm_connect(conn, hostname, port, (ping || opt_verbose) ? &tv1 : NULL) < 0) { if (errno == 0) { fprintf(stderr, "client: ERROR: Cannot connect to %s:%d: Host unknown.\n", hostname, port); } else { char tbuf[BUFSIZ]; snprintf(tbuf, BUFSIZ, "client: ERROR: Cannot connect to %s:%d", hostname, port); perror(tbuf); } exit(1); } /* Send the HTTP request */ bytesWritten = mywrite(conn, msg, strlen(msg)); if (bytesWritten < 0) { perror("client: ERROR: write"); exit(1); } else if (bytesWritten != strlen(msg)) { fprintf(stderr, "client: ERROR: Cannot send request?: %s\n", msg); exit(1); } if (put_file) { int x; lseek(put_fd, 0, SEEK_SET); #ifdef _SQUID_MSWIN_ while ((x = read(put_fd, buf, sizeof(buf))) > 0) { #else while ((x = myread(put_fd, buf, sizeof(buf))) > 0) { #endif x = mywrite(conn, buf, x); total_bytes += x; if (x <= 0) break; } if (x != 0) fprintf(stderr, "client: ERROR: Cannot send file.\n"); } /* Read the data */ #ifdef _SQUID_MSWIN_ setmode(1, O_BINARY); #endif while ((len = myread(conn, buf, sizeof(buf))) > 0) { fsize += len; if (to_stdout) fwrite(buf, len, 1, stdout); } #ifdef _SQUID_MSWIN_ setmode(1, O_TEXT); #endif (void) close(conn); /* done with socket */ if (interrupted) break; if (ping || opt_verbose) { struct tm *tmp; time_t t2s; long elapsed_msec; (void) Now(&tv2); elapsed_msec = tvSubMsec(tv1, tv2); t2s = tv2.tv_sec; tmp = localtime(&t2s); fprintf(stderr, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s (%" PRINTF_OFF_T "KB)\n", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, i + 1, elapsed_msec / 1000, elapsed_msec % 1000, elapsed_msec ? (double) fsize / elapsed_msec * 1000 / 1024 : -1.0, (fsize + 1023) / 1024); if (i == 0 || elapsed_msec < ping_min) ping_min = elapsed_msec; if (i == 0 || elapsed_msec > ping_max) ping_max = elapsed_msec; ping_sum += elapsed_msec; /* Delay until next "ping_int" boundary */ if (ping && (loops == 0 || i + 1 < loops) && elapsed_msec < ping_int) { struct timeval tvs; long msec_left = ping_int - elapsed_msec; tvs.tv_sec = msec_left / 1000; tvs.tv_usec = (msec_left % 1000) * 1000; select(0, NULL, NULL, NULL, &tvs); } } } if (ping && i) { ping_mean = ping_sum / i; fprintf(stderr, "%d requests, round-trip (secs) min/avg/max = " "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i, ping_min / 1000, ping_min % 1000, ping_mean / 1000, ping_mean % 1000, ping_max / 1000, ping_max % 1000); } exit(0); /*NOTREACHED */ return 0; } static int client_comm_bind(int sock, const char *local_host) { static const struct hostent *hp = NULL; static struct sockaddr_in from_addr; /* Set up the source socket address from which to send. */ if (hp == NULL) { from_addr.sin_family = AF_INET; if ((hp = gethostbyname(local_host)) == 0) { return (-1); } xmemcpy(&from_addr.sin_addr, hp->h_addr, hp->h_length); from_addr.sin_port = 0; } return bind(sock, (struct sockaddr *) &from_addr, sizeof(struct sockaddr_in)); } static int client_comm_connect(int sock, const char *dest_host, u_short dest_port, struct timeval *tvp) { static const struct hostent *hp = NULL; static struct sockaddr_in to_addr; /* Set up the destination socket address for message to send to. */ if (hp == NULL) { to_addr.sin_family = AF_INET; if ((hp = gethostbyname(dest_host)) == 0) { return (-1); } xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length); to_addr.sin_port = htons(dest_port); } if (tvp) (void) Now(tvp); return connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in)); } static int Now(struct timeval *tp) { #if GETTIMEOFDAY_NO_TZP return gettimeofday(tp); #else return gettimeofday(tp, NULL); #endif } /* ARGSUSED */ static void catchSignal(int sig) { interrupted = 1; fprintf(stderr, "Interrupted.\n"); }
/* return 1 if the entry must be revalidated within delta seconds * 0 otherwise * * note: request maybe null (e.g. for cache digests build) */ static int refreshCheck(const StoreEntry * entry, request_t * request, time_t delta) { const refresh_t *R; const char *uri = NULL; time_t age = 0; time_t check_time = squid_curtime; int staleness; stale_flags sf; if (entry->mem_obj) uri = entry->mem_obj->url; else if (request) uri = urlCanonical(request); debug(22, 3) ("refreshCheck: '%s'\n", uri ? uri : "<none>"); if (delta > 0) check_time += delta; if (check_time > entry->timestamp) age = check_time - entry->timestamp; R = uri ? refreshLimits(uri) : refreshUncompiledPattern("."); if (NULL == R) R = &DefaultRefresh; memset(&sf, '\0', sizeof(sf)); staleness = refreshStaleness(entry, check_time, age, R, &sf); debug(22, 3) ("Staleness = %d\n", staleness); debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n", R->pattern, (int) R->min, (int) (100.0 * R->pct), (int) R->max); debug(22, 3) ("refreshCheck: age = %d\n", (int) age); debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time)); debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp)); if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1) { debug(22, 3) ("refreshCheck: YES: Must revalidate stale response\n"); return STALE_MUST_REVALIDATE; } /* request-specific checks */ if (request) { HttpHdrCc *cc = request->cache_control; #if HTTP_VIOLATIONS if (!request->flags.nocache_hack) { (void) 0; } else if (R->flags.ignore_reload) { /* The clients no-cache header is ignored */ debug(22, 3) ("refreshCheck: MAYBE: ignore-reload\n"); } else if (R->flags.reload_into_ims || Config.onoff.reload_into_ims) { /* The clients no-cache header is changed into a IMS query */ debug(22, 3) ("refreshCheck: YES: reload-into-ims\n"); return STALE_RELOAD_INTO_IMS; } else { /* The clients no-cache header is not overridden on this request */ debug(22, 3) ("refreshCheck: YES: client reload\n"); request->flags.nocache = 1; return STALE_FORCED_RELOAD; } #endif if (NULL != cc) { if (cc->max_age > -1) { #if HTTP_VIOLATIONS if (R->flags.ignore_reload && cc->max_age == 0) { } else #endif if (age > cc->max_age) { debug(22, 3) ("refreshCheck: YES: age > client-max-age\n"); return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; } } if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness >= 0) { if (cc->max_stale < 0) { /* max-stale directive without a value */ debug(22, 3) ("refreshCheck: NO: max-stale wildcard\n"); return FRESH_REQUEST_MAX_STALE_ALL; } else if (staleness < cc->max_stale) { debug(22, 3) ("refreshCheck: NO: staleness < max-stale\n"); return FRESH_REQUEST_MAX_STALE_VALUE; } } } } if (staleness < 0) { if (sf.expires) return FRESH_EXPIRES; assert(!sf.max); if (sf.lmfactor) return FRESH_LMFACTOR_RULE; assert(sf.min); return FRESH_MIN_RULE; } /* * At this point the response is stale, unless one of * the override options kicks in. */ if (delta < 0 && staleness + delta < 0) { return STALE_WITHIN_DELTA; } if (sf.expires) { #if HTTP_VIOLATIONS if (R->flags.override_expire && age < R->min) { debug(22, 3) ("refreshCheck: NO: age < min && override-expire\n"); return FRESH_OVERRIDE_EXPIRES; } #endif return STALE_EXPIRES; } if (sf.max) return STALE_MAX_RULE; if (sf.lmfactor) { #if HTTP_VIOLATIONS if (R->flags.override_lastmod && age < R->min) { debug(22, 3) ("refreshCheck: NO: age < min && override-lastmod\n"); return FRESH_OVERRIDE_LASTMOD; } #endif return STALE_LMFACTOR_RULE; } return STALE_DEFAULT; }
/* * 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. * * The 'stale_flags' structure is used to tell the calling function * _why_ this response is fresh or stale. Its used, for example, * when the admin wants to override expiration and last-modified * times. */ static int refreshStaleness(const StoreEntry * entry, time_t check_time, time_t age, const refresh_t * R, stale_flags * sf) { /* * Check for an explicit expiration time. */ if (entry->expires > -1) { sf->expires = 1; if (entry->expires > check_time) { debug(22, 3) ("FRESH: expires %d >= check_time %d \n", (int) entry->expires, (int) check_time); return -1; } else { debug(22, 3) ("STALE: expires %d < check_time %d \n", (int) entry->expires, (int) check_time); return (check_time - entry->expires); } } assert(age >= 0); /* * Use local heuristics to determine staleness. Start with the * max age from the refresh_pattern rule. */ if (age > R->max) { debug(22, 3) ("STALE: age %d > max %d \n", (int) age, (int) R->max); sf->max = 1; return (age - R->max); } if (check_time < entry->timestamp) { debug(22, 1) ("STALE: Entry's timestamp greater than check time. Clock going backwards?\n"); debug(22, 1) ("\tcheck_time:\t%s\n", mkrfc1123(check_time)); debug(22, 1) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp)); debug(22, 1) ("\tstaleness:\t%ld\n", (long int) entry->timestamp - check_time); return (entry->timestamp - check_time); } /* * Try the last-modified factor algorithm. */ if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) { /* * stale_age is the Age of the response when it became/becomes * stale according to the last-modified factor algorithm. */ time_t stale_age = (entry->timestamp - entry->lastmod) * R->pct; sf->lmfactor = 1; if (age >= stale_age) { debug(22, 3) ("STALE: age %d > stale_age %d\n", (int) age, (int) stale_age); return (age - stale_age); } else { debug(22, 3) ("FRESH: age %d <= stale_age %d\n", (int) age, (int) stale_age); return -1; } } /* * If we are here, staleness is determined by the refresh_pattern * configured minimum age. */ if (age <= R->min) { debug(22, 3) ("FRESH: age %d <= min %d\n", (int) age, (int) R->min); sf->min = 1; return -1; } debug(22, 3) ("STALE: age %d > min %d\n", (int) age, (int) R->min); return (age - R->min); }