mod_cache_disk.c revision 62fcfb7e08b7057daaabce98fbf9631401696fa6
0ad489b182ebb3789322345e22cf750f88ae167and/* Licensed to the Apache Software Foundation (ASF) under one or more
0ad489b182ebb3789322345e22cf750f88ae167and * contributor license agreements. See the NOTICE file distributed with
0ad489b182ebb3789322345e22cf750f88ae167and * this work for additional information regarding copyright ownership.
0a05fab9aadd37834734ffe106fc8ad4488fb3e3rbowen * The ASF licenses this file to You under the Apache License, Version 2.0
0ad489b182ebb3789322345e22cf750f88ae167and * (the "License"); you may not use this file except in compliance with
0ad489b182ebb3789322345e22cf750f88ae167and * the License. You may obtain a copy of the License at
031b91a62d25106ae69d4693475c79618dd5e884fielding * Unless required by applicable law or agreed to in writing, software
031b91a62d25106ae69d4693475c79618dd5e884fielding * distributed under the License is distributed on an "AS IS" BASIS,
031b91a62d25106ae69d4693475c79618dd5e884fielding * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0ad489b182ebb3789322345e22cf750f88ae167and * See the License for the specific language governing permissions and
0ad489b182ebb3789322345e22cf750f88ae167and * limitations under the License.
0ad489b182ebb3789322345e22cf750f88ae167and * mod_cache_disk: Disk Based HTTP 1.1 Cache.
0ad489b182ebb3789322345e22cf750f88ae167and * Flow to Find the .data file:
0ad489b182ebb3789322345e22cf750f88ae167and * Incoming client requests URI /foo/bar/baz
0ad489b182ebb3789322345e22cf750f88ae167and * Generate <hash> off of /foo/bar/baz
0ad489b182ebb3789322345e22cf750f88ae167and * Open <hash>.header
0ad489b182ebb3789322345e22cf750f88ae167and * Read in <hash>.header file (may contain Format #1 or Format #2)
0ad489b182ebb3789322345e22cf750f88ae167and * If format #1 (Contains a list of Vary Headers):
0ad489b182ebb3789322345e22cf750f88ae167and * Use each header name (from .header) with our request values (headers_in) to
0ad489b182ebb3789322345e22cf750f88ae167and * regenerate <hash> using HeaderName+HeaderValue+.../foo/bar/baz
0ad489b182ebb3789322345e22cf750f88ae167and * re-read in <hash>.header (must be format #2)
0ad489b182ebb3789322345e22cf750f88ae167and * read in <hash>.data
0ad489b182ebb3789322345e22cf750f88ae167and * Format #1:
0ad489b182ebb3789322345e22cf750f88ae167and * apr_uint32_t format;
0ad489b182ebb3789322345e22cf750f88ae167and * apr_time_t expire;
0ad489b182ebb3789322345e22cf750f88ae167and * apr_array_t vary_headers (delimited by CRLF)
0ad489b182ebb3789322345e22cf750f88ae167and * Format #2:
0ad489b182ebb3789322345e22cf750f88ae167and * disk_cache_info_t (first sizeof(apr_uint32_t) bytes is the format)
0ad489b182ebb3789322345e22cf750f88ae167and * entity name (dobj->name) [length is in disk_cache_info_t->name_len]
0ad489b182ebb3789322345e22cf750f88ae167and * r->headers_out (delimited by CRLF)
0ad489b182ebb3789322345e22cf750f88ae167and * r->headers_in (delimited by CRLF)
0ad489b182ebb3789322345e22cf750f88ae167and/* Forward declarations */
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info *i);
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *in,
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t recall_headers(cache_handle_t *h, request_rec *r);
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t read_array(request_rec *r, apr_array_header_t* arr,
0ad489b182ebb3789322345e22cf750f88ae167and * Local static functions
0ad489b182ebb3789322345e22cf750f88ae167andstatic char *header_file(apr_pool_t *p, disk_cache_conf *conf,
0ad489b182ebb3789322345e22cf750f88ae167and dobj->hashfile = ap_cache_generate_name(p, conf->dirlevels,
0ad489b182ebb3789322345e22cf750f88ae167and return apr_pstrcat(p, dobj->prefix, CACHE_VDIR_SUFFIX, "/",
0ad489b182ebb3789322345e22cf750f88ae167and return apr_pstrcat(p, conf->cache_root, "/", dobj->hashfile,
0ad489b182ebb3789322345e22cf750f88ae167andstatic char *data_file(apr_pool_t *p, disk_cache_conf *conf,
0ad489b182ebb3789322345e22cf750f88ae167and dobj->hashfile = ap_cache_generate_name(p, conf->dirlevels,
0ad489b182ebb3789322345e22cf750f88ae167and return apr_pstrcat(p, dobj->prefix, CACHE_VDIR_SUFFIX, "/",
0ad489b182ebb3789322345e22cf750f88ae167and return apr_pstrcat(p, conf->cache_root, "/", dobj->hashfile,
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t mkdir_structure(disk_cache_conf *conf, const char *file, apr_pool_t *pool)
0ad489b182ebb3789322345e22cf750f88ae167and *p = '\0';
0ad489b182ebb3789322345e22cf750f88ae167and/* htcacheclean may remove directories underneath us.
0ad489b182ebb3789322345e22cf750f88ae167and * So, we'll try renaming three times at a cost of 0.002 seconds.
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t safe_file_rename(disk_cache_conf *conf,
0ad489b182ebb3789322345e22cf750f88ae167and /* 1000 micro-seconds aka 0.001 seconds. */
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t file_cache_el_final(disk_cache_conf *conf, disk_cache_file_t *file,
0ad489b182ebb3789322345e22cf750f88ae167and /* This assumes that the tempfiles are on the same file system
0ad489b182ebb3789322345e22cf750f88ae167and * as the cache_root. If not, then we need a file copy/move
0ad489b182ebb3789322345e22cf750f88ae167and * rather than a rename.
0ad489b182ebb3789322345e22cf750f88ae167and /* move the file over */
0ad489b182ebb3789322345e22cf750f88ae167and rv = safe_file_rename(conf, file->tempfile, file->file, file->pool);
0ad489b182ebb3789322345e22cf750f88ae167and ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00699)
0ad489b182ebb3789322345e22cf750f88ae167and "rename tempfile to file failed:"
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t file_cache_temp_cleanup(void *dummy) {
0ad489b182ebb3789322345e22cf750f88ae167and /* clean up the temporary file */
0ad489b182ebb3789322345e22cf750f88ae167andstatic apr_status_t file_cache_create(disk_cache_conf *conf, disk_cache_file_t *file,
0ad489b182ebb3789322345e22cf750f88ae167and file->tempfile = apr_pstrcat(pool, conf->cache_root, AP_TEMPFILE, NULL);
0ad489b182ebb3789322345e22cf750f88ae167and apr_pool_cleanup_register(pool, file, file_cache_temp_cleanup, apr_pool_cleanup_null);
0ad489b182ebb3789322345e22cf750f88ae167and/* These two functions get and put state information into the data
0ad489b182ebb3789322345e22cf750f88ae167and * file for an ap_cache_el, this state information will be read
0ad489b182ebb3789322345e22cf750f88ae167and * and written transparent to clients of this module
5e4ea7442ef8c03184c727a39fc03e240b239b74rbowenstatic int file_cache_recall_mydata(apr_file_t *fd, cache_info *info,
0ad489b182ebb3789322345e22cf750f88ae167and /* read the data from the cache file */
0ad489b182ebb3789322345e22cf750f88ae167and rv = apr_file_read_full(fd, &dobj->disk_info, len, &len);
0ad489b182ebb3789322345e22cf750f88ae167and /* Store it away so we can get it later. */
0ad489b182ebb3789322345e22cf750f88ae167and memcpy(&info->control, &dobj->disk_info.control, sizeof(cache_control_t));
0ad489b182ebb3789322345e22cf750f88ae167and /* Note that we could optimize this by conditionally doing the palloc
0ad489b182ebb3789322345e22cf750f88ae167and * depending upon the size. */
0ad489b182ebb3789322345e22cf750f88ae167and urlbuff = apr_palloc(r->pool, dobj->disk_info.name_len + 1);
return APR_EGENERAL;
return APR_SUCCESS;
int nvec;
const char *header;
const char **elts;
if (!header) {
char *token;
sizeof(char *), array_alphasort);
return DECLINED;
key);
return DECLINED;
return DECLINED;
return DECLINED;
return OK;
const char *nkey;
static int error_logged = 0;
#ifdef APR_SENDFILE_ENABLED
int flags;
if (!error_logged) {
return DECLINED;
return DECLINED;
return DECLINED;
return DECLINED;
return DECLINED;
return DECLINED;
return DECLINED;
#ifdef APR_SENDFILE_ENABLED
return DECLINED;
return OK;
return OK;
return DECLINED;
return OK;
if (!dobj) {
return DECLINED;
return DECLINED;
return DECLINED;
const char *str_to_copy;
if (str_to_copy) {
return OK;
char w[MAX_STRING_LEN];
return rv;
p = strlen(w);
return APR_SUCCESS;
const char **elts;
return rv;
char w[MAX_STRING_LEN];
return rv;
p = strlen(w);
++maybeEBCDIC;
++maybeASCII;
r->filename);
return APR_EGENERAL;
while (*l && apr_isspace(*l)) {
return APR_SUCCESS;
return APR_NOTFOUND;
return APR_SUCCESS;
return APR_SUCCESS;
return rv;
return rv;
if (r->headers_out) {
if (r->headers_in) {
return APR_SUCCESS;
const char *tmp;
if (tmp) {
return rv;
return rv;
return rv;
return rv;
return rv;
return rv;
return rv;
return rv;
return rv;
return APR_SUCCESS;
apr_bucket *e;
int seen_eos = 0;
const char *str;
if (APR_BUCKET_IS_EOS(e)) {
if (APR_BUCKET_IS_FLUSH(e)) {
if (APR_BUCKET_IS_METADATA(e)) {
return rv;
if (!length) {
return rv;
return rv;
return rv;
return APR_EGENERAL;
if (seen_eos) {
return rv;
return APR_EGENERAL;
return APR_EGENERAL;
if (cl_header) {
return APR_EGENERAL;
return APR_SUCCESS;
remove_url(h, r);
return APR_SUCCESS;
return APR_ENOTIMPL;
return dconf;
return new;
return conf;
return NULL;
return NULL;
return NULL;
return "CacheMinFileSize argument must be a non-negative integer representing the min size of a file to cache in bytes.";
return NULL;
return "CacheMaxFileSize argument must be a non-negative integer representing the max size of a file to cache in bytes.";
return NULL;
return "CacheReadSize argument must be a non-negative integer representing the max amount of data to cache in go.";
return NULL;
milliseconds < 0)
return "CacheReadTime argument must be a non-negative integer representing the max amount of time taken to cache in go.";
return NULL;
{NULL}