mod_disk_cache.c revision 2e7ef6efb7164346000607d5b5c2d2d392d1a5ea
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#include "mod_cache.h"
#include "apr_file_io.h"
#include "apr_strings.h"
#include "util_filter.h"
#include "util_script.h"
#endif
/*
* disk_cache_object_t
* Pointed to by cache_object_t::vobj
*/
typedef struct disk_cache_object {
const char *root; /* the location of the cache directory */
char *tempfile; /* temp file tohold the content */
#if 0
int dirlevels; /* Number of levels of subdirectories */
int dirlength; /* Length of subdirectory names */
#endif
char *datafile; /* name of file where the data will go */
char *hdrsfile; /* name of file where the hdrs will go */
char *name;
/*
* mod_disk_cache configuration
*/
/* TODO: Make defaults OS specific */
#define DEFAULT_DIRLEVELS 3
#define DEFAULT_DIRLENGTH 2
#define DEFAULT_MIN_FILE_SIZE 1
#define DEFAULT_MAX_FILE_SIZE 1000000
#define DEFAULT_CACHE_SIZE 1000000
typedef struct {
const char* cache_root;
double lmfactor; /* factor for estimating expires date */
int dirlevels; /* Number of levels of subdirectories */
int dirlength; /* Length of subdirectory names */
int expirychk; /* true if expiry time is observed for cached files */
/* dgc_time_t gcdt; time of day for daily garbage collection */
int maxgcmem; /* maximum memory used by garbage collection */
/* Forward declarations */
static int remove_entity(cache_handle_t *h);
/*
* Local static functions
*/
#define CACHE_HEADER_SUFFIX ".header"
#define CACHE_DATA_SUFFIX ".data"
{
char *hashfile;
}
{
char *hashfile;
}
{
char *p;
p = strchr(p, '/');
if (!p)
break;
*p = '\0';
/* XXX */
}
*p = '/';
++p;
}
}
{
/* move the data over */
}
/* Remove old file with the same name. If remove fails, then
* perhaps we need to create the directory tree where we are
* about to write the new file.
*/
if (rv != APR_SUCCESS) {
}
/*
* This assumes that the tempfile is on the same file system
* rather than a rename.
*/
if (rv != APR_SUCCESS) {
/* XXX log */
}
/* XXX log */
}
return APR_SUCCESS;
}
/* These two functions get and put state information into the data
* file for an ap_cache_el, this state information will be read
* and written transparent to clients of this module
*/
{
int offset=0;
char * temp;
/* read the data from the cache file */
/* format
* date SP expire SP count CRLF
* dates are stored as a hex representation of apr_time_t (number of
* microseconds since 00:00:00 january 1, 1970 UTC)
*/
if (rv != APR_SUCCESS) {
return rv;
}
if (!apr_date_checkmask(urlbuff, "&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&")) {
return APR_EGENERAL;
}
/* check that we have the same URL */
if (rv != APR_SUCCESS) {
return rv;
}
}
return APR_EGENERAL;
}
return APR_EGENERAL;
}
return APR_SUCCESS;
}
{
char *buf;
if (!r->headers_out) {
/* XXX log message */
return 0;
}
buf = apr_pstrcat(r->pool, dateHexS, " ", expireHexS, " ", verHexS, " ", requestHexS, " ", responseHexS, "\n", NULL);
if (rc != APR_SUCCESS) {
/* XXX log message */
return 0;
}
if (rc != APR_SUCCESS) {
/* XXX log message */
return 0;
}
return 1;
}
/*
* Hook and mod_cache callback functions
*/
#define AP_TEMPFILE "/aptmpXXXXXX"
const char *type,
const char *key,
{
return DECLINED;
}
return DECLINED;
}
"cache_disk: URL %s failed the size check, "
"or is incomplete",
key);
return DECLINED;
}
/* Allocate and initialize cache_object_t and disk_cache_object_t */
/* XXX Bad Temporary Cast - see cache_object_t notes */
/* open temporary file */
if (rv == APR_SUCCESS) {
/* Populate the cache handle */
h->read_headers = &read_headers;
h->write_body = &write_body;
h->write_headers = &write_headers;
h->remove_entity = &remove_entity;
"disk_cache: Caching URL %s", key);
}
else {
return DECLINED;
}
return OK;
}
{
static int error_logged = 0;
char *data;
char *headers;
apr_file_t *fd;
/* Look up entity keyed to 'url' */
return DECLINED;
}
if (!error_logged) {
error_logged = 1;
"disk_cache: Cannot cache files to disk without a CacheRoot specified.");
}
return DECLINED;
}
/* Open the data file */
if (rc != APR_SUCCESS) {
/* XXX: Log message */
return DECLINED;
}
/* Open the headers file */
if (rc != APR_SUCCESS) {
/* XXX: Log message */
return DECLINED;
}
/* Create and init the cache object */
if (rc == APR_SUCCESS) {
}
/* Read the bytes to setup the cache_info fields */
if (rc != APR_SUCCESS) {
/* XXX log message */
return DECLINED;
}
/* Initialize the cache_handle callback functions */
h->read_headers = &read_headers;
h->write_body = &write_body;
h->write_headers = &write_headers;
h->remove_entity = &remove_entity;
return OK;
}
static int remove_entity(cache_handle_t *h)
{
/* Null out the cache object pointer so next time we start from scratch */
return OK;
}
/*
* Reads headers from a buffer and returns an array of headers.
* Returns NULL on file error
* This routine tries to deal with too long lines and continuation lines.
* @@@: XXX: FIXME: currently the headers are passed thru un-merged.
* Is that okay, or should they be collapsed where possible?
*/
{
char urlbuff[1034];
apr_table_t * tmp;
/* This case should not happen... */
/* XXX log message */
return APR_NOTFOUND;
}
if(!r->headers_out) {
}
/*
*/
ap_make_content_type(r, r->content_type));
if (rv != APR_SUCCESS) {
/* XXX log message */
return rv;
}
/* Read and ignore the status line (This request might result in a
* 304, so we don't necessarily want to retransmit a 200 from the cache.)
*/
if (rv != APR_SUCCESS) {
/* XXX log message */
return rv;
}
/*
*/
tmp = r->err_headers_out;
r->err_headers_out = h->req_hdrs;
r->err_headers_out = tmp;
return APR_SUCCESS;
}
{
apr_bucket *e;
bb->bucket_alloc);
return APR_SUCCESS;
}
{
char *buf;
char statusbuf[8];
if (!hfd) {
}
/* This is flaky... we need to manage the cache_info differently */
/* Remove old file with the same name. If remove fails, then
* perhaps we need to create the directory tree where we are
* about to write the new headers file.
*/
if (rv != APR_SUCCESS) {
}
APR_OS_DEFAULT, r->pool);
if (rv != APR_SUCCESS) {
return rv;
}
if (r->headers_out) {
int i;
}
}
/* This case only occurs when the content is generated locally */
ap_make_content_type(r, r->content_type));
}
}
/* This case only occurs when the content is generated locally */
if (!r->status_line) {
}
/* Parse the vary header and dump those fields from the headers_in. */
/* Make call to the same thing cache_select_url calls to crack Vary. */
/* @@@ Some day, not today. */
if (r->headers_in) {
int i;
}
}
}
}
else {
/* XXX log message */
}
return APR_SUCCESS;
}
{
apr_bucket *e;
if (rv != APR_SUCCESS) {
return rv;
}
}
for (e = APR_BRIGADE_FIRST(b);
e != APR_BRIGADE_SENTINEL(b);
e = APR_BUCKET_NEXT(e))
{
const char *str;
}
if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(b))) {
file_cache_el_final(h, r); /* Link to the perm file, and close the descriptor */
}
return APR_SUCCESS;
}
{
/* XXX: Set default values */
conf->cache_root_len = 0;
return conf;
}
/*
* mod_disk_cache configuration directives handlers.
*/
static const char
{
/* TODO: canonicalize cache_root and strip off any trailing slashes */
return NULL;
}
static const char
{
return NULL;
}
static const char
{
/*
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&disk_cache_module);
*/
/* XXX */
return NULL;
}
/*
* Consider eliminating the next two directives in favor of
* Ian's prime number hash...
* key = hash_fn( r->uri)
*/
static const char
{
if (val < 1)
return "CacheDirLevels value must be an integer greater than 0";
return "CacheDirLevels*CacheDirLength value must not be higher than 20";
return NULL;
}
static const char
{
if (val < 1)
return "CacheDirLength value must be an integer greater than 0";
return "CacheDirLevels*CacheDirLength value must not be higher than 20";
return NULL;
}
static const char
{
return NULL;
}
static const char
{
return NULL;
}
static const char
{
return NULL;
}
static const char
{
/* XXX
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&disk_cache_module);
*/
return NULL;
}
static const char
{
/* XXX
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&disk_cache_module);
*/
return NULL;
}
static const char
{
/* XXX
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&disk_cache_module);
*/
return NULL;
}
static const char
{
/* XXX
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&disk_cache_module);
*/
return NULL;
}
static const char
{
/* XXX
disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
&disk_cache_module);
*/
return NULL;
}
static const command_rec disk_cache_cmds[] =
{
"The directory to store cache files"),
"The maximum disk space used by the cache in KB"),
"The interval between garbage collections, in hours"),
"The number of levels of subdirectories in the cache"),
"The number of characters in subdirectory names"),
"on if cache observes Expires date when seeking files"),
"The minimum file size to cache a document"),
"The maximum file size to cache a document"),
"The minimum time margin to cache a document"),
"The time of day for garbage collection (24 hour clock)"),
"The time in hours to retain unused file that match a url"),
"The time in hours to retain unchanged files that match a url"),
"The maximum kilobytes of memory used for garbage collection"),
{NULL}
};
static void disk_cache_register_hook(apr_pool_t *p)
{
/* cache initializer */
/* cache_hook_remove_entity(remove_entity, NULL, NULL, APR_HOOK_MIDDLE); */
}
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
create_config, /* create per-server config structure */
NULL, /* merge per-server config structures */
disk_cache_cmds, /* command apr_table_t */
disk_cache_register_hook /* register hooks */
};