/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
/* These two functions get and put state information into the data *fileforanap_cache_el,thisstateinformationwillberead *andwrittentransparenttoclientsofthismodule
*/ staticint file_cache_recall_mydata(apr_file_t *fd, cache_info *info,
disk_cache_object_t *dobj, request_rec *r)
{
apr_status_t rv; char *urlbuff;
apr_size_t len;
/* read the data from the cache file */
len = sizeof(disk_cache_info_t);
rv = apr_file_read_full(fd, &dobj->disk_info, len, &len); if (rv != APR_SUCCESS) { return rv;
}
/* Store it away so we can get it later. */
info->status = dobj->disk_info.status;
info->date = dobj->disk_info.date;
info->expire = dobj->disk_info.expire;
info->request_time = dobj->disk_info.request_time;
info->response_time = dobj->disk_info.response_time;
/* Note that we could optimize this by conditionally doing the palloc
* depending upon the size. */
urlbuff = apr_palloc(r->pool, dobj->disk_info.name_len + 1);
len = dobj->disk_info.name_len;
rv = apr_file_read_full(fd, urlbuff, len, &len); if (rv != APR_SUCCESS) { return rv;
}
urlbuff[dobj->disk_info.name_len] = '\0';
/* check that we have the same URL */ /* Would strncmp be correct? */ if (strcmp(urlbuff, dobj->name) != 0) { return APR_EGENERAL;
}
return APR_SUCCESS;
}
staticconstchar* regen_key(apr_pool_t *p, apr_table_t *headers,
apr_array_header_t *varray, constchar *oldkey)
{ struct iovec *iov; int i, k; int nvec; constchar *header; constchar **elts;
/* Look up entity keyed to 'url' */ if (conf->cache_root == NULL) { if (!error_logged) {
error_logged = 1;
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00703) "Cannot cache files to disk without a CacheRoot specified.");
} return DECLINED;
}
/* Create and init the cache object */
obj = apr_pcalloc(r->pool, sizeof(cache_object_t));
dobj = apr_pcalloc(r->pool, sizeof(disk_cache_object_t));
info = &(obj->info);
/* Open the headers file */
dobj->prefix = NULL;
/* Save the cache root */
dobj->root = apr_pstrmemdup(r->pool, conf->cache_root, conf->cache_root_len);
dobj->root_len = conf->cache_root_len;
/* oops, not vary as it turns out */
dobj->hdrs.fd = dobj->vary.fd;
dobj->vary.fd = NULL;
dobj->hdrs.file = dobj->vary.file;
/* This wasn't a Vary Format file, so we must seek to the *startofthefileagain,sothatlaterreadswork.
*/
apr_file_seek(dobj->hdrs.fd, APR_SET, &offset);
nkey = key;
}
/* Read the bytes to setup the cache_info fields */
rc = file_cache_recall_mydata(dobj->hdrs.fd, info, dobj, r); if (rc != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(00706) "Cannot read header file %s", dobj->hdrs.file);
apr_file_close(dobj->hdrs.fd); return DECLINED;
}
/* Is this a cached HEAD request? */ if (dobj->disk_info.header_only && !r->header_only) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00707) "HEAD request cached, non-HEAD requested, ignoring: %s",
dobj->hdrs.file);
apr_file_close(dobj->hdrs.fd); return DECLINED;
}
/* Open the data file */ if (dobj->disk_info.has_body) {
flags = APR_READ | APR_BINARY; #ifdef APR_SENDFILE_ENABLED /* When we are in the quick handler we don't have the per-directory *configuration,sothischeckonlytakestheglobalsettingof *theEnableSendFiledirectiveintoaccount.
*/
flags |= AP_SENDFILE_ENABLED(coreconf->enable_sendfile); #endif
rc = apr_file_open(&dobj->data.fd, dobj->data.file, flags, 0, r->pool); if (rc != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(00708) "Cannot open data file %s", dobj->data.file);
apr_file_close(dobj->hdrs.fd); return DECLINED;
}
/* Atomic check - does the body file belong to the header file? */ if (dobj->disk_info.inode == finfo.inode &&
dobj->disk_info.device == finfo.device) {
/* Initialize the cache_handle callback functions */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00709) "Recalled cached URL info header %s", dobj->name);
/* make the configuration stick */
h->cache_obj = obj;
obj->vobj = dobj;
return OK;
}
} else {
/* make the configuration stick */
h->cache_obj = obj;
obj->vobj = dobj;
return OK;
}
/* Oh dear, no luck matching header to the body */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00710) "Cached URL info header '%s' didn't match body, ignoring this entry",
dobj->name);
/* Get disk cache object from cache handle */
dobj = (disk_cache_object_t *) h->cache_obj->vobj; if (!dobj) { return DECLINED;
}
/* Delete headers file */ if (dobj->hdrs.file) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00711) "Deleting %s from cache.", dobj->hdrs.file);
rc = apr_file_remove(dobj->hdrs.file, r->pool); if ((rc != APR_SUCCESS) && !APR_STATUS_IS_ENOENT(rc)) { /* Will only result in an output if httpd is started with -e debug. *Forreasonseelog_error_coreforthecases==NULL.
*/
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rc, r, APLOGNO(00712) "Failed to delete headers file %s from cache.",
dobj->hdrs.file); return DECLINED;
}
}
/* Delete data file */ if (dobj->data.file) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00713) "Deleting %s from cache.", dobj->data.file);
rc = apr_file_remove(dobj->data.file, r->pool); if ((rc != APR_SUCCESS) && !APR_STATUS_IS_ENOENT(rc)) { /* Will only result in an output if httpd is started with -e debug. *Forreasonseelog_error_coreforthecases==NULL.
*/
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rc, r, APLOGNO(00714) "Failed to delete data file %s from cache.",
dobj->data.file); return DECLINED;
}
}
/* now delete directories as far as possible up to our cache root */ if (dobj->root) { constchar *str_to_copy;
/* If we've finished reading the headers, break out of the loop. */ if (w[0] == '\0') { break;
}
#if APR_CHARSET_EBCDIC /* Chances are that we received an ASCII header text instead of *theexpectedEBCDICheaderlines.Trytoauto-detect:
*/ if (!(l = strchr(w, ':'))) { int maybeASCII = 0, maybeEBCDIC = 0; unsignedchar *cp, native;
apr_size_t inbytes_left, outbytes_left;
/* This case should not happen... */ if (!dobj->hdrs.fd) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00719) "recalling headers; but no header fd for %s", dobj->name); return APR_NOTFOUND;
}
if (tmp) {
apr_array_header_t* varray;
apr_uint32_t format = VARY_FORMAT_VERSION;
/* If we were initially opened as a vary format, rollback *thatinternalstateforthemomentsowecanrecreatethe *varyformathintsintheappropriatedirectory.
*/ if (dobj->prefix) {
dobj->hdrs.file = dobj->prefix;
dobj->prefix = NULL;
}
rv = apr_file_writev_full(dobj->hdrs.tempfd, (conststruct iovec *) &iov, 2, &amt); if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00726) "could not write info to header file %s",
dobj->hdrs.tempfile);
apr_file_close(dobj->hdrs.tempfd);
apr_pool_destroy(dobj->hdrs.pool); return rv;
}
if (dobj->headers_out) {
rv = store_table(dobj->hdrs.tempfd, dobj->headers_out); if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00727) "could not write out-headers to header file %s",
dobj->hdrs.tempfile);
apr_file_close(dobj->hdrs.tempfd);
apr_pool_destroy(dobj->hdrs.pool); return rv;
}
}
/* Parse the vary header and dump those fields from the headers_in. */ /* FIXME: Make call to the same thing cache_select calls to crack Vary. */ if (dobj->headers_in) {
rv = store_table(dobj->hdrs.tempfd, dobj->headers_in); if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00728) "could not write in-headers to header file %s",
dobj->hdrs.tempfile);
apr_file_close(dobj->hdrs.tempfd);
apr_pool_destroy(dobj->hdrs.pool); return rv;
}
}
rv = apr_file_close(dobj->hdrs.tempfd); /* flush and close */ if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00729) "could not close header file %s",
dobj->hdrs.tempfile);
apr_pool_destroy(dobj->hdrs.pool); return rv;
}
/* are we done completely? if so, pass any trailing buckets right through */ if (dobj->done || !dobj->data.pool) {
APR_BUCKET_REMOVE(e);
APR_BRIGADE_INSERT_TAIL(out, e); continue;
}
/* have we seen eos yet? */ if (APR_BUCKET_IS_EOS(e)) {
seen_eos = 1;
dobj->done = 1;
APR_BUCKET_REMOVE(e);
APR_BRIGADE_INSERT_TAIL(out, e); break;
}
/* honour flush buckets, we'll get called again */ if (APR_BUCKET_IS_FLUSH(e)) {
APR_BUCKET_REMOVE(e);
APR_BRIGADE_INSERT_TAIL(out, e); break;
}
/* metadata buckets are preserved as is */ if (APR_BUCKET_IS_METADATA(e)) {
APR_BUCKET_REMOVE(e);
APR_BRIGADE_INSERT_TAIL(out, e); continue;
}
/* read the bucket, write to the cache */
rv = apr_bucket_read(e, &str, &length, APR_BLOCK_READ);
APR_BUCKET_REMOVE(e);
APR_BRIGADE_INSERT_TAIL(out, e); if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00730) "Error when reading bucket for URL %s",
h->cache_obj->key); /* Remove the intermediate cache file and return non-APR_SUCCESS */
apr_pool_destroy(dobj->data.pool); return rv;
}
/* don't write empty buckets to the cache */ if (!length) { continue;
}
if (!dobj->disk_info.header_only) {
/* Attempt to create the data file at the last possible moment, if *thebodyisempty,wedon'twriteafileatall,andsaveaninode.
*/ if (!dobj->data.tempfd) {
apr_finfo_t finfo;
rv = apr_file_mktemp(&dobj->data.tempfd, dobj->data.tempfile,
APR_CREATE | APR_WRITE | APR_BINARY | APR_BUFFERED
| APR_EXCL, dobj->data.pool); if (rv != APR_SUCCESS) {
apr_pool_destroy(dobj->data.pool); return rv;
}
dobj->file_size = 0;
rv = apr_file_info_get(&finfo, APR_FINFO_IDENT,
dobj->data.tempfd); if (rv != APR_SUCCESS) {
apr_pool_destroy(dobj->data.pool); return rv;
}
dobj->disk_info.device = finfo.device;
dobj->disk_info.inode = finfo.inode;
dobj->disk_info.has_body = 1;
}
/* write to the cache, leave if we fail */
rv = apr_file_write_full(dobj->data.tempfd, str, length, &written); if (rv != APR_SUCCESS) {
ap_log_rerror(
APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00731) "Error when writing cache file for URL %s", h->cache_obj->key); /* Remove the intermediate cache file and return non-APR_SUCCESS */
apr_pool_destroy(dobj->data.pool); return rv;
}
dobj->file_size += written; if (dobj->file_size > dconf->maxfs) {
ap_log_rerror(
APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00732) "URL %s failed the size check " "(%" APR_OFF_T_FMT ">%" APR_OFF_T_FMT ")", h->cache_obj->key, dobj->file_size, dconf->maxfs); /* Remove the intermediate cache file and return non-APR_SUCCESS */
apr_pool_destroy(dobj->data.pool); return APR_EGENERAL;
}
}
/* have we reached the limit of how much we're prepared to write in one *go?Ifso,leave,we'llgetcalledagain.Thispreventsusfromtrying *toswallowtoomuchdataatonce,ortakingsolongtowritethedata *theclienttimesout.
*/
dobj->offset -= length; if (dobj->offset <= 0) {
dobj->offset = 0; break;
} if ((dconf->readtime && apr_time_now() > dobj->timeout)) {
dobj->timeout = 0; break;
}
}
/* Was this the final bucket? If yes, close the temp file and perform *sanitychecks.
*/ if (seen_eos) { if (!dobj->disk_info.header_only) { constchar *cl_header;
apr_off_t cl;
if (dobj->data.tempfd) {
rv = apr_file_close(dobj->data.tempfd); if (rv != APR_SUCCESS) { /* Buffered write failed, abandon attempt to write */
apr_pool_destroy(dobj->data.pool); return rv;
}
}
if (r->connection->aborted || r->no_cache) {
ap_log_rerror(
APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00733) "Discarding body for URL %s " "because connection has been aborted.", h->cache_obj->key); /* Remove the intermediate cache file and return non-APR_SUCCESS */
apr_pool_destroy(dobj->data.pool); return APR_EGENERAL;
}
if (dobj->file_size < dconf->minfs) {
ap_log_rerror(
APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00734) "URL %s failed the size check " "(%" APR_OFF_T_FMT "<%" APR_OFF_T_FMT ")", h->cache_obj->key, dobj->file_size, dconf->minfs); /* Remove the intermediate cache file and return non-APR_SUCCESS */
apr_pool_destroy(dobj->data.pool); return APR_EGENERAL;
}
/* write the headers to disk at the last possible moment */
rv = write_headers(h, r);
/* move header and data tempfiles to the final destination */ if (APR_SUCCESS == rv) {
rv = file_cache_el_final(conf, &dobj->hdrs, r);
} if (APR_SUCCESS == rv) {
rv = file_cache_el_final(conf, &dobj->vary, r);
} if (APR_SUCCESS == rv) { if (!dobj->disk_info.header_only) {
rv = file_cache_el_final(conf, &dobj->data, r);
} elseif (dobj->data.file) {
rv = apr_file_remove(dobj->data.file, dobj->data.pool);
}
}
/* remove the cached items completely on any failure */ if (APR_SUCCESS != rv) {
remove_url(h, r);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00736) "commit_entity: URL '%s' not cached due to earlier disk error.",
dobj->name);
} else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00737) "commit_entity: Headers and body for URL %s cached.",
dobj->name);
}
/* *Considereliminatingthenexttwodirectivesinfavorof *Ian'sprimenumberhash... *key=hash_fn(r->uri) *filename="/key%prime1/key%prime2/key%prime3"
*/ staticconstchar
*set_cache_dirlevels(cmd_parms *parms, void *in_struct_ptr, constchar *arg)
{
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&cache_disk_module); int val = atoi(arg); if (val < 1) return"CacheDirLevels value must be an integer greater than 0"; if (val * conf->dirlength > CACHEFILE_LEN) return"CacheDirLevels*CacheDirLength value must not be higher than 20";
conf->dirlevels = val; return NULL;
} staticconstchar
*set_cache_dirlength(cmd_parms *parms, void *in_struct_ptr, constchar *arg)
{
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&cache_disk_module); int val = atoi(arg); if (val < 1) return"CacheDirLength value must be an integer greater than 0"; if (val * conf->dirlevels > CACHEFILE_LEN) return"CacheDirLevels*CacheDirLength value must not be higher than 20";
if (apr_strtoff(&dconf->minfs, arg, NULL, 10) != APR_SUCCESS ||
dconf->minfs < 0)
{ return"CacheMinFileSize argument must be a non-negative integer representing the min size of a file to cache in bytes.";
}
dconf->minfs_set = 1; return NULL;
}
if (apr_strtoff(&dconf->maxfs, arg, NULL, 10) != APR_SUCCESS ||
dconf->maxfs < 0)
{ return"CacheMaxFileSize argument must be a non-negative integer representing the max size of a file to cache in bytes.";
}
dconf->maxfs_set = 1; return NULL;
}
if (apr_strtoff(&dconf->readsize, arg, NULL, 10) != APR_SUCCESS ||
dconf->readsize < 0)
{ return"CacheReadSize argument must be a non-negative integer representing the max amount of data to cache in go.";
}
dconf->readsize_set = 1; return NULL;
}
if (apr_strtoff(&milliseconds, arg, NULL, 10) != APR_SUCCESS ||
milliseconds < 0)
{ return"CacheReadTime argument must be a non-negative integer representing the max amount of time taken to cache in go.";
}
dconf->readtime = apr_time_from_msec(milliseconds);
dconf->readtime_set = 1; return NULL;
}
staticconst command_rec disk_cache_cmds[] =
{
AP_INIT_TAKE1("CacheRoot", set_cache_root, NULL, RSRC_CONF, "The directory to store cache files"),
AP_INIT_TAKE1("CacheDirLevels", set_cache_dirlevels, NULL, RSRC_CONF, "The number of levels of subdirectories in the cache"),
AP_INIT_TAKE1("CacheDirLength", set_cache_dirlength, NULL, RSRC_CONF, "The number of characters in subdirectory names"),
AP_INIT_TAKE1("CacheMinFileSize", set_cache_minfs, NULL, RSRC_CONF | ACCESS_CONF, "The minimum file size to cache a document"),
AP_INIT_TAKE1("CacheMaxFileSize", set_cache_maxfs, NULL, RSRC_CONF | ACCESS_CONF, "The maximum file size to cache a document"),
AP_INIT_TAKE1("CacheReadSize", set_cache_readsize, NULL, RSRC_CONF | ACCESS_CONF, "The maximum quantity of data to attempt to read and cache in one go"),
AP_INIT_TAKE1("CacheReadTime", set_cache_readtime, NULL, RSRC_CONF | ACCESS_CONF, "The maximum time taken to attempt to read and cache in go"),
{NULL}
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.