static time_t httpReplyHdrExpirationTime_(const HttpReply * rep) { if (rep->cache_control) { if (rep->date >= 0) { if (rep->cache_control->s_maxage >= 0) return rep->date + rep->cache_control->s_maxage; if (rep->cache_control->max_age >= 0) return rep->date + rep->cache_control->max_age; } else { if (rep->cache_control->s_maxage >= 0) return squid_curtime; if (rep->cache_control->max_age >= 0) return squid_curtime; } } if (Config.onoff.vary_ignore_expire && httpHeaderHas(&rep->header, HDR_VARY)) { const time_t d = httpHeaderGetTime(&rep->header, HDR_DATE); const time_t e = httpHeaderGetTime(&rep->header, HDR_EXPIRES); if (d == e) return -1; } if (httpHeaderHas(&rep->header, HDR_EXPIRES)) { const time_t e = httpHeaderGetTime(&rep->header, HDR_EXPIRES); return e < 0 ? squid_curtime : e; } return -1; }
/* returns true if connection should be "persistent" * after processing this message */ int httpMsgIsPersistent(http_version_t http_ver, const HttpHeader * hdr) { if (httpHeaderHasConnDir(hdr, "close")) return 0; #if WHEN_SQUID_IS_HTTP1_1 if ((http_ver.major >= 1) && (http_ver.minor >= 1)) { /* * for modern versions of HTTP: persistent unless there is * a "Connection: close" header. */ return 1; } else { #else { #endif /* * Persistent connections in Netscape 3.x are allegedly broken, * return false if it is a browser connection. If there is a * VIA header, then we assume this is NOT a browser connection. */ const char *agent = httpHeaderGetStr(hdr, HDR_USER_AGENT); if (agent && !httpHeaderHas(hdr, HDR_VIA)) { if (!strncasecmp(agent, "Mozilla/3.", 10)) return 0; if (!strncasecmp(agent, "Netscape/3.", 11)) return 0; } /* for old versions of HTTP: persistent if has "keep-alive" */ return httpHeaderHasConnDir(hdr, "keep-alive"); } }
int refreshIsCachable(const StoreEntry * entry) { /* * Don't look at the request to avoid no-cache and other nuisances. * the object should have a mem_obj so the URL will be found there. * 60 seconds delta, to avoid objects which expire almost * immediately, and which can't be refreshed. */ int reason = refreshCheck(entry, NULL, Config.minimum_expiry_time); int can_revalidate = 0; refreshCounts[rcStore].total++; refreshCounts[rcStore].status[reason]++; if (reason < 200) /* Does not need refresh. This is certainly cachable */ return 1; if (entry->lastmod > 0) can_revalidate = 1; if (entry->mem_obj && entry->mem_obj->reply) { if (httpHeaderHas(&entry->mem_obj->reply->header, HDR_ETAG)) can_revalidate = 1; } /* Last modified is needed to do a refresh */ if (!can_revalidate) return 0; /* This seems to be refreshable. Cache it */ return 1; }
/* * return true if a given directive is found in at least one of * the "connection" header-fields note: if HDR_PROXY_CONNECTION is * present we ignore HDR_CONNECTION. */ int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive) { String list; http_hdr_type ht; int res; /* what type of header do we have? */ if (httpHeaderHas(hdr, HDR_PROXY_CONNECTION)) ht = HDR_PROXY_CONNECTION; else if (httpHeaderHas(hdr, HDR_CONNECTION)) ht = HDR_CONNECTION; else return 0; list = httpHeaderGetList(hdr, ht); res = strListIsMember(&list, directive, ','); stringClean(&list); return res; }
static time_t httpReplyHdrExpirationTime(const HttpReply * rep) { /* The s-maxage and max-age directive takes priority over Expires */ if (rep->cache_control) { if (rep->date >= 0) { if (rep->cache_control->s_maxage >= 0) return rep->date + rep->cache_control->s_maxage; if (rep->cache_control->max_age >= 0) return rep->date + rep->cache_control->max_age; } else { /* * Conservatively handle the case when we have a max-age * header, but no Date for reference? */ if (rep->cache_control->s_maxage >= 0) return squid_curtime; if (rep->cache_control->max_age >= 0) return squid_curtime; } } if (Config.onoff.vary_ignore_expire && httpHeaderHas(&rep->header, HDR_VARY)) { const time_t d = httpHeaderGetTime(&rep->header, HDR_DATE); const time_t e = httpHeaderGetTime(&rep->header, HDR_EXPIRES); if (d == e) return -1; } if (httpHeaderHas(&rep->header, HDR_EXPIRES)) { const time_t e = httpHeaderGetTime(&rep->header, HDR_EXPIRES); /* * HTTP/1.0 says that robust implementations should consider * bad or malformed Expires header as equivalent to "expires * immediately." */ return e < 0 ? squid_curtime : e; } return -1; }
/* * The helper program receives queries on stdin, one * per line, and must return the result on on stdout */ static void refreshCheckHandleReply(void *data, char *reply) { refreshCheckState *state = data; refreshCheckState *next; int freshness = -1; char *log = NULL; MemBuf hdrs = MemBufNULL; debug(84, 2) ("refreshCheckHandleReply: reply=\"%s\"\n", reply); if (reply) { char *t = NULL; char *token = strwordtok(reply, &t); if (token && strcmp(token, "FRESH") == 0) freshness = 0; else if (token && strcmp(token, "OK") == 0) freshness = 0; while ((token = strwordtok(NULL, &t))) { char *value = strchr(token, '='); if (value) { *value++ = '\0'; /* terminate the token, and move up to the value */ rfc1738_unescape(value); if (strcmp(token, "freshness") == 0) freshness = atoi(value); else if (strcmp(token, "log") == 0) log = value; else if (strncmp(token, "res{", 4) == 0) { char *header, *t; header = token + 4; t = strrchr(header, '}'); if (!t) continue; *t = '\0'; if (!hdrs.buf) memBufDefInit(&hdrs); memBufPrintf(&hdrs, "%s: %s\r\n", header, value); } } } } if (freshness >= 0) { if (hdrs.size) { HttpReply *rep = httpReplyCreate(); httpHeaderParse(&rep->header, hdrs.buf, hdrs.buf + hdrs.size); httpReplyUpdateOnNotModified(state->entry->mem_obj->reply, rep); storeTimestampsSet(state->entry); if (!httpHeaderHas(&rep->header, HDR_DATE)) { state->entry->timestamp = squid_curtime; state->entry->expires = squid_curtime + freshness; } else if (freshness) { state->entry->expires = squid_curtime + freshness; } httpReplyDestroy(rep); storeUpdate(state->entry, NULL); } else { state->entry->timestamp = squid_curtime; state->entry->expires = squid_curtime + freshness; } } if (hdrs.buf) memBufClean(&hdrs); dlinkDelete(&state->list, &state->def->queue); do { cbdataUnlock(state->def); state->def = NULL; if (state->callback && cbdataValid(state->callback_data)) state->callback(state->callback_data, freshness >= 0, log); cbdataUnlock(state->callback_data); state->callback_data = NULL; next = state->queue; cbdataFree(state); state = next; } while (state); }