📄 proxy_cache.c
字号:
char *name = vary; const char *h1, *h2; /* isolate header name */ while (*vary && !ap_isspace(*vary) && (*vary != ',')) ++vary; while (*vary && (ap_isspace(*vary) || (*vary == ','))) { *vary = '\0'; ++vary; } /* * is this header in the request and the header in the cached * request identical? If not, we give up and do a straight get */ h1 = ap_table_get(r->headers_in, name); h2 = ap_table_get(c->req_hdrs, name); if (h1 == h2) { /* both headers NULL, so a match - do nothing */ } else if (h1 && h2 && !strcmp(h1, h2)) { /* both headers exist and are equal - do nothing */ } else { /* headers do not match, so Vary failed */ c->fp = cachefp; ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Vary header mismatch - object must be fetched from scratch. Declining."); return DECLINED; } } } /* * We now want to check if our cached data is still fresh. This depends * on a few things, in this order: * * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache no-cache in * either the request or the cached response means that we must * revalidate the request unconditionally, overriding any expiration * mechanism. It's equivalent to max-age=0,must-revalidate. * * - RFC2616 14.32 Pragma: no-cache This is treated the same as * Cache-Control: no-cache. * * - RFC2616 14.9.3 Cache-Control: max-stale, must-revalidate, * proxy-revalidate if the max-stale request header exists, modify the * stale calculations below so that an object can be at most <max-stale> * seconds stale before we request a revalidation, _UNLESS_ a * must-revalidate or proxy-revalidate cached response header exists to * stop us doing this. * * - RFC2616 14.9.3 Cache-Control: s-maxage the origin server specifies the * maximum age an object can be before it is considered stale. This * directive has the effect of proxy|must revalidate, which in turn means * simple ignore any max-stale setting. * * - RFC2616 14.9.4 Cache-Control: max-age this header can appear in both * requests and responses. If both are specified, the smaller of the two * takes priority. * * - RFC2616 14.21 Expires: if this request header exists in the cached * entity, and it's value is in the past, it has expired. * */ /* calculate age of object */ age = ap_proxy_current_age(c, age_c); /* extract s-maxage */ if (cc_cresp && ap_proxy_liststr(cc_cresp, "s-maxage", &val)) smaxage = atoi(val); else smaxage = -1; /* extract max-age from request */ if (cc_req && ap_proxy_liststr(cc_req, "max-age", &val)) maxage_req = atoi(val); else maxage_req = -1; /* extract max-age from response */ if (cc_cresp && ap_proxy_liststr(cc_cresp, "max-age", &val)) maxage_cresp = atoi(val); else maxage_cresp = -1; /* * if both maxage request and response, the smaller one takes priority */ if (-1 == maxage_req) maxage = maxage_cresp; else if (-1 == maxage_cresp) maxage = maxage_req; else maxage = MIN(maxage_req, maxage_cresp); /* extract max-stale */ if (cc_req && ap_proxy_liststr(cc_req, "max-stale", &val)) maxstale = atoi(val); else maxstale = 0; /* extract min-fresh */ if (cc_req && ap_proxy_liststr(cc_req, "min-fresh", &val)) minfresh = atoi(val); else minfresh = 0; /* override maxstale if must-revalidate or proxy-revalidate */ if (maxstale && ((cc_cresp && ap_proxy_liststr(cc_cresp, "must-revalidate", NULL)) || (cc_cresp && ap_proxy_liststr(cc_cresp, "proxy-revalidate", NULL)))) maxstale = 0; if (cachefp != NULL && /* handle no-cache */ !((cc_req && ap_proxy_liststr(cc_req, "no-cache", NULL)) || (pragma_req && ap_proxy_liststr(pragma_req, "no-cache", NULL)) || (cc_cresp && ap_proxy_liststr(cc_cresp, "no-cache", NULL)) || (pragma_cresp && ap_proxy_liststr(pragma_cresp, "no-cache", NULL))) && /* handle expiration */ ((-1 < smaxage && age < (smaxage - minfresh)) || (-1 < maxage && age < (maxage + maxstale - minfresh)) || (c->expire != BAD_DATE && age < (c->expire - c->date + maxstale - minfresh))) ) { /* it's fresh darlings... */ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Unexpired data available"); /* set age header on response */ ap_table_set(c->hdrs, "Age", ap_psprintf(r->pool, "%lu", (unsigned long)age)); /* add warning if maxstale overrode freshness calculation */ if (!((-1 < smaxage && age < smaxage) || (-1 < maxage && age < maxage) || (c->expire != BAD_DATE && (c->expire - c->date) > age))) { /* make sure we don't stomp on a previous warning */ ap_table_merge(c->hdrs, "Warning", "110 Response is stale"); } /* check conditionals (If-Modified-Since, etc) */ c->xcache = ap_pstrcat(r->pool, "HIT from ", ap_get_server_name(r), NULL); return ap_proxy_cache_conditional(r, c, cachefp); } /* * at this point we have determined our cached data needs revalidation * but first - we check 1 thing: * * RFC2616 14.9.4 - if "only-if-cached" specified, send a 504 Gateway * Timeout - we're not allowed to revalidate the object */ if (ap_proxy_liststr(cc_req, "only-if-cached", NULL)) { if (cachefp) ap_pclosef(r->pool, ap_bfileno(cachefp, B_WR)); return HTTP_GATEWAY_TIME_OUT; } /* * If we already have cached data and a last-modified date, and it is not * a head request, then add an If-Modified-Since. * * If we also have an Etag, then the object must have come from an HTTP/1.1 * server. Add an If-None-Match as well. * * See RFC2616 13.3.4 */ if (cachefp != NULL && !r->header_only) { const char *etag = ap_table_get(c->hdrs, "Etag"); /* If-Modified-Since */ if (c->lmod != BAD_DATE) { /* * use the later of the one from the request and the * last-modified date from the cache */ if (c->ims == BAD_DATE || c->ims < c->lmod) { const char *q; if ((q = ap_table_get(c->hdrs, "Last-Modified")) != NULL) ap_table_set(r->headers_in, "If-Modified-Since", (char *)q); } } /* If-None-Match */ if (etag) { ap_table_set(r->headers_in, "If-None-Match", etag); } } c->fp = cachefp; ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Local copy not present or expired. Declining."); return DECLINED;}/* * Having read the response from the client, decide what to do * If the response is not cachable, then delete any previously cached * response, and copy data from remote server to client. * Functions: * parse dates * check for an uncachable response * calculate an expiry date, if one is not provided * if the remote file has not been modified, then return the document * from the cache, maybe updating the header line * otherwise, delete the old cached file and open a new temporary file */int ap_proxy_cache_update(cache_req *c, table *resp_hdrs, const int is_HTTP1, int nocache){#if defined(ULTRIX_BRAIN_DEATH) || defined(SINIX_D_RESOLVER_BUG) extern char *mktemp(char *template);#endif request_rec *r = c->req; char *p; const char *expire, *lmods, *dates, *clen; time_t expc, date, lmod, now; char buff[17 * 7 + 1]; void *sconf = r->server->module_config; proxy_server_conf *conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module); const char *cc_resp; table *req_hdrs; cc_resp = ap_table_get(resp_hdrs, "Cache-Control"); c->tempfile = NULL; /* we've received the response from the origin server */ /* * read expiry date; if a bad date, then leave it so the client can read * it */ expire = ap_table_get(resp_hdrs, "Expires"); if (expire != NULL) expc = ap_parseHTTPdate(expire); else expc = BAD_DATE; /* read the last-modified date; if the date is bad, then delete it */ lmods = ap_table_get(resp_hdrs, "Last-Modified"); if (lmods != NULL) { lmod = ap_parseHTTPdate(lmods); if (lmod == BAD_DATE) { /* kill last modified date */ lmods = NULL; } } else lmod = BAD_DATE; /* * what responses should we not cache? * * At this point we decide based on the response headers whether it is * appropriate _NOT_ to cache the data from the server. There are a whole * lot of conditions that prevent us from caching this data. They are * tested here one by one to be clear and unambiguous. */ /* * RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410 We * don't cache 206, because we don't (yet) cache partial responses. We * include 304 Not Modified here too as this is the origin server telling * us to serve the cached copy. */ if ((r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE && r->status != HTTP_MULTIPLE_CHOICES && r->status != HTTP_MOVED_PERMANENTLY && r->status != HTTP_NOT_MODIFIED) || /* if a broken Expires header is present, don't cache it */ (expire != NULL && expc == BAD_DATE) || /* * if the server said 304 Not Modified but we have no cache file - pass * this untouched to the user agent, it's not for us. */ (r->status == HTTP_NOT_MODIFIED && (c == NULL || c->fp == NULL)) || /* * 200 OK response from HTTP/1.0 and up without a Last-Modified header */ (r->status == HTTP_OK && lmods == NULL && is_HTTP1) || /* HEAD requests */ r->header_only || /* * RFC2616 14.9.2 Cache-Control: no-store response indicating do not * cache, or stop now if you are trying to cache it */ ap_proxy_liststr(cc_resp, "no-store", NULL) || /* * RFC2616 14.9.1 Cache-Control: private this object is marked for this * user's eyes only. Behave as a tunnel. */ ap_proxy_liststr(cc_resp, "private", NULL) || /* * RFC2616 14.8 Authorisation: if authorisation is included in the * request, we don't cache, but we can cache if the following exceptions * are true: 1) If Cache-Control: s-maxage is included 2) If * Cache-Control: must-revalidate is included 3) If Cache-Control: public * is included */ (ap_table_get(r->headers_in, "Authorization") != NULL && !(ap_proxy_liststr(cc_resp, "s-maxage", NULL) || ap_proxy_liststr(cc_resp, "must-revalidate", NULL) || ap_proxy_liststr(cc_resp, "public", NULL)) ) || /* or we've been asked not to cache it above */ nocache) { ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Response is not cacheable, unlinking %s", c->filename); /* close the file */ if (c->fp != NULL) { ap_pclosef(r->pool, ap_bfileno(c->fp, B_WR)); c->fp = NULL; } /* delete the previously cached file */ if (c->filename) unlink(c->filename); return DECLINED; /* send data to client but not cache */ } /* * It's safe to cache the response. * * We now want to update the cache file header information with the new * date, last modified, expire and content length and write it away to * our cache file. First, we determine these values from the response, * using heuristics if appropriate. * * In addition, we make HTTP/1.1 age calculations and write them away too. */ /* Read the date. Generate one if one is not supplied */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -