📄 proxy_cache.c
字号:
}/* * 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){#ifdef ULTRIX_BRAIN_DEATH extern char *mktemp(char *template);#endif request_rec *r = c->req; char *p; int i; const char *expire, *lmods, *dates, *clen; time_t expc, date, lmod, now; char buff[46]; void *sconf = r->server->module_config; proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); const long int zero = 0L; c->tempfile = NULL;/* we've received the response *//* 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? * Unknown status responses and those known to be uncacheable * 304 HTTP_NOT_MODIFIED response when we have no valid cache file, or * 200 HTTP_OK response from HTTP/1.0 and up without a Last-Modified header, or * HEAD requests, or * requests with an Authorization header, or * protocol requests nocache (e.g. ftp with user/password) *//* @@@ XXX FIXME: is the test "r->status != HTTP_MOVED_PERMANENTLY" corerct? * or shouldn't it be "ap_is_HTTP_REDIRECT(r->status)" ? -MnKr */ if ((r->status != HTTP_OK && r->status != HTTP_MOVED_PERMANENTLY && r->status != HTTP_NOT_MODIFIED) || (expire != NULL && expc == BAD_DATE) || (r->status == HTTP_NOT_MODIFIED && (c == NULL || c->fp == NULL)) || (r->status == HTTP_OK && lmods == NULL && is_HTTP1) || r->header_only || ap_table_get(r->headers_in, "Authorization") != NULL || nocache) { Explain1("Response is not cacheable, unlinking %s", c->filename);/* close the file */ if (c->fp != NULL) { ap_pclosef(r->pool, c->fp->fd); c->fp = NULL; }/* delete the previously cached file */ if (c->filename) unlink(c->filename); return DECLINED; /* send data to client but not cache */ }/* otherwise, we are going to cache the response *//* * Read the date. Generate one if one is not supplied */ dates = ap_table_get(resp_hdrs, "Date"); if (dates != NULL) date = ap_parseHTTPdate(dates); else date = BAD_DATE; now = time(NULL); if (date == BAD_DATE) { /* No, or bad date *//* no date header! *//* add one; N.B. use the time _now_ rather than when we were checking the cache */ date = now; dates = ap_gm_timestr_822(r->pool, now); ap_table_set(resp_hdrs, "Date", dates); Explain0("Added date header"); }/* check last-modified date */ if (lmod != BAD_DATE && lmod > date)/* if its in the future, then replace by date */ { lmod = date; lmods = dates; Explain0("Last modified is in the future, replacing with now"); }/* if the response did not contain the header, then use the cached version */ if (lmod == BAD_DATE && c->fp != NULL) { lmod = c->lmod; Explain0("Reusing cached last modified"); }/* we now need to calculate the expire data for the object. */ if (expire == NULL && c->fp != NULL) { /* no expiry data sent in response */ expire = ap_table_get(c->hdrs, "Expires"); if (expire != NULL) expc = ap_parseHTTPdate(expire); }/* so we now have the expiry date *//* if no expiry date then * if lastmod * expiry date = now + min((date - lastmod) * factor, maxexpire) * else * expire date = now + defaultexpire */ Explain1("Expiry date is %ld", expc); if (expc == BAD_DATE) { if (lmod != BAD_DATE) { double x = (double) (date - lmod) * conf->cache.lmfactor; double maxex = conf->cache.maxexpire; if (x > maxex) x = maxex; expc = now + (int) x; } else expc = now + conf->cache.defaultexpire; Explain1("Expiry date calculated %ld", expc); }/* get the content-length header */ clen = ap_table_get(resp_hdrs, "Content-Length"); if (clen == NULL) c->len = -1; else c->len = atoi(clen); ap_proxy_sec2hex(date, buff); buff[8] = ' '; ap_proxy_sec2hex(lmod, buff + 9); buff[17] = ' '; ap_proxy_sec2hex(expc, buff + 18); buff[26] = ' '; ap_proxy_sec2hex(c->version++, buff + 27); buff[35] = ' '; ap_proxy_sec2hex(c->len, buff + 36); buff[44] = '\n'; buff[45] = '\0';/* if file not modified */ if (r->status == HTTP_NOT_MODIFIED) { if (c->ims != BAD_DATE && lmod != BAD_DATE && lmod <= c->ims) {/* set any changed headers somehow *//* update dates and version, but not content-length */ if (lmod != c->lmod || expc != c->expire || date != c->date) { off_t curpos = lseek(c->fp->fd, 0, SEEK_SET); if (curpos == -1) ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error seeking on cache file %s", c->filename); else if (write(c->fp->fd, buff, 35) == -1) ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error updating cache file %s", c->filename); } ap_pclosef(r->pool, c->fp->fd); Explain0("Remote document not modified, use local copy"); /* CHECKME: Is this right? Shouldn't we check IMS again here? */ return HTTP_NOT_MODIFIED; } else {/* return the whole document */ Explain0("Remote document updated, sending"); r->status_line = strchr(c->resp_line, ' ') + 1; r->status = c->status; if (!r->assbackwards) { ap_soft_timeout("proxy send headers", r); ap_proxy_send_headers(r, c->resp_line, c->hdrs); ap_kill_timeout(r); } ap_bsetopt(r->connection->client, BO_BYTECT, &zero); r->sent_bodyct = 1; if (!r->header_only) ap_proxy_send_fb(c->fp, r, NULL);/* set any changed headers somehow *//* update dates and version, but not content-length */ if (lmod != c->lmod || expc != c->expire || date != c->date) { off_t curpos = lseek(c->fp->fd, 0, SEEK_SET); if (curpos == -1) ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error seeking on cache file %s", c->filename); else if (write(c->fp->fd, buff, 35) == -1) ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error updating cache file %s", c->filename); } ap_pclosef(r->pool, c->fp->fd); return OK; } }/* new or modified file */ if (c->fp != NULL) { ap_pclosef(r->pool, c->fp->fd); c->fp->fd = -1; } c->version = 0; ap_proxy_sec2hex(0, buff + 27); buff[35] = ' ';/* open temporary file */#define TMPFILESTR "/tmpXXXXXX" if (conf->cache.root == NULL) return DECLINED; c->tempfile = ap_palloc(r->pool, strlen(conf->cache.root) + sizeof(TMPFILESTR)); strcpy(c->tempfile, conf->cache.root); strcat(c->tempfile, TMPFILESTR);#undef TMPFILESTR p = mktemp(c->tempfile); if (p == NULL) return DECLINED; Explain1("Create temporary file %s", c->tempfile); i = open(c->tempfile, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0622); if (i == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error creating cache file %s", c->tempfile); return DECLINED; } ap_note_cleanups_for_fd(r->pool, i); c->fp = ap_bcreate(r->pool, B_WR); ap_bpushfd(c->fp, -1, i); if (ap_bvputs(c->fp, buff, "X-URL: ", c->url, "\n", NULL) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error writing cache file(%s)", c->tempfile); ap_pclosef(r->pool, c->fp->fd); unlink(c->tempfile); c->fp = NULL; } return DECLINED;}void ap_proxy_cache_tidy(cache_req *c){ server_rec *s; long int bc; if (c == NULL || c->fp == NULL) return; s = c->req->server;/* don't care how much was sent, but rather how much was written to cache ap_bgetopt(c->req->connection->client, BO_BYTECT, &bc); */ bc = c->written; if (c->len != -1) {/* file lengths don't match; don't cache it */ if (bc != c->len) { ap_pclosef(c->req->pool, c->fp->fd); /* no need to flush */ unlink(c->tempfile); return; } }/* don't care if aborted, cache it if fully retrieved from host! else if (c->req->connection->aborted) { ap_pclosef(c->req->pool, c->fp->fd); / no need to flush / unlink(c->tempfile); return; }*/ else {/* update content-length of file */ char buff[9]; off_t curpos; c->len = bc; ap_bflush(c->fp); ap_proxy_sec2hex(c->len, buff); curpos = lseek(c->fp->fd, 36, SEEK_SET); if (curpos == -1) ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error seeking on cache file %s", c->tempfile); else if (write(c->fp->fd, buff, 8) == -1) ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error updating cache file %s", c->tempfile); } if (ap_bflush(c->fp) == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error writing to cache file %s", c->tempfile); ap_pclosef(c->req->pool, c->fp->fd); unlink(c->tempfile); return; } if (ap_pclosef(c->req->pool, c->fp->fd) == -1) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error closing cache file %s", c->tempfile); unlink(c->tempfile); return; } if (unlink(c->filename) == -1 && errno != ENOENT) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error deleting old cache file %s", c->tempfile); } else { char *p; proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module); for (p = c->filename + strlen(conf->cache.root) + 1;;) { p = strchr(p, '/'); if (!p) break; *p = '\0';#ifdef WIN32 if (mkdir(c->filename) < 0 && errno != EEXIST)#else if (mkdir(c->filename, S_IREAD | S_IWRITE | S_IEXEC) < 0 && errno != EEXIST)#endif /* WIN32 */ ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error creating cache directory %s", c->filename); *p = '/'; ++p; }#if defined(OS2) || defined(WIN32) /* Under OS/2 use rename. */ if (rename(c->tempfile, c->filename) == -1) ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error renaming cache file %s to %s", c->tempfile, c->filename); }#else if (link(c->tempfile, c->filename) == -1) ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error linking cache file %s to %s", c->tempfile, c->filename); } if (unlink(c->tempfile) == -1) ap_log_error(APLOG_MARK, APLOG_ERR, s, "proxy: error deleting temp file %s", c->tempfile);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -