summaryrefslogtreecommitdiff
path: root/modules/experimental
diff options
context:
space:
mode:
Diffstat (limited to 'modules/experimental')
-rw-r--r--modules/experimental/.cvsignore16
-rw-r--r--modules/experimental/.indent.pro54
-rw-r--r--modules/experimental/Makefile.in3
-rw-r--r--modules/experimental/README41
-rw-r--r--modules/experimental/cache_storage.c268
-rw-r--r--modules/experimental/cache_util.c303
-rw-r--r--modules/experimental/config.m479
-rw-r--r--modules/experimental/mod_auth_ldap.c862
-rw-r--r--modules/experimental/mod_auth_ldap.def6
-rw-r--r--modules/experimental/mod_cache.c995
-rw-r--r--modules/experimental/mod_cache.dsp119
-rw-r--r--modules/experimental/mod_cache.h305
-rw-r--r--modules/experimental/mod_case_filter.c112
-rw-r--r--modules/experimental/mod_case_filter_in.c196
-rw-r--r--modules/experimental/mod_charset_lite.c1118
-rw-r--r--modules/experimental/mod_charset_lite.exp1
-rw-r--r--modules/experimental/mod_deflate.c464
-rw-r--r--modules/experimental/mod_deflate.exp1
-rw-r--r--modules/experimental/mod_disk_cache.c814
-rw-r--r--modules/experimental/mod_disk_cache.dsp111
-rw-r--r--modules/experimental/mod_example.c1343
-rw-r--r--modules/experimental/mod_ext_filter.c794
-rw-r--r--modules/experimental/mod_ext_filter.exp1
-rw-r--r--modules/experimental/mod_mem_cache.c890
-rw-r--r--modules/experimental/mod_mem_cache.dsp111
-rw-r--r--modules/experimental/util_ldap.c1104
-rw-r--r--modules/experimental/util_ldap.def6
-rw-r--r--modules/experimental/util_ldap_cache.c309
-rw-r--r--modules/experimental/util_ldap_cache.h214
-rw-r--r--modules/experimental/util_ldap_cache_mgr.c537
30 files changed, 0 insertions, 11177 deletions
diff --git a/modules/experimental/.cvsignore b/modules/experimental/.cvsignore
deleted file mode 100644
index aeabff36e6..0000000000
--- a/modules/experimental/.cvsignore
+++ /dev/null
@@ -1,16 +0,0 @@
-.deps
-.libs
-*.la
-modules.mk
-Makefile
-*.lo
-*.slo
-*.so
-*.x
-Debug
-Release
-*.plg
-*.aps
-*.dep
-*.mak
-*.rc
diff --git a/modules/experimental/.indent.pro b/modules/experimental/.indent.pro
deleted file mode 100644
index a9fbe9f9a1..0000000000
--- a/modules/experimental/.indent.pro
+++ /dev/null
@@ -1,54 +0,0 @@
--i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
--TBUFF
--TFILE
--TTRANS
--TUINT4
--T_trans
--Tallow_options_t
--Tapache_sfio
--Tarray_header
--Tbool_int
--Tbuf_area
--Tbuff_struct
--Tbuffy
--Tcmd_how
--Tcmd_parms
--Tcommand_rec
--Tcommand_struct
--Tconn_rec
--Tcore_dir_config
--Tcore_server_config
--Tdir_maker_func
--Tevent
--Tglobals_s
--Thandler_func
--Thandler_rec
--Tjoblist_s
--Tlisten_rec
--Tmerger_func
--Tmode_t
--Tmodule
--Tmodule_struct
--Tmutex
--Tn_long
--Tother_child_rec
--Toverrides_t
--Tparent_score
--Tpid_t
--Tpiped_log
--Tpool
--Trequest_rec
--Trequire_line
--Trlim_t
--Tscoreboard
--Tsemaphore
--Tserver_addr_rec
--Tserver_rec
--Tserver_rec_chain
--Tshort_score
--Ttable
--Ttable_entry
--Tthread
--Tu_wide_int
--Tvtime_t
--Twide_int
diff --git a/modules/experimental/Makefile.in b/modules/experimental/Makefile.in
deleted file mode 100644
index 7c5c149d85..0000000000
--- a/modules/experimental/Makefile.in
+++ /dev/null
@@ -1,3 +0,0 @@
-# a modules Makefile has no explicit targets -- they will be defined by
-# whatever modules are enabled. just grab special.mk to deal with this.
-include $(top_srcdir)/build/special.mk
diff --git a/modules/experimental/README b/modules/experimental/README
deleted file mode 100644
index 1d80fa5855..0000000000
--- a/modules/experimental/README
+++ /dev/null
@@ -1,41 +0,0 @@
-README for Apache 2.0 Example Module
-[April, 1997, updated May 2000]
-
-The files in the src/modules/example directory under the Apache
-distribution directory tree are provided as an example to those that
-wish to write modules that use the Apache API.
-
-The main file is mod_example.c, which illustrates all the different
-callback mechanisms and call syntaces. By no means does an add-on
-module need to include routines for all of the callbacks - quite the
-contrary!
-
-The example module is an actual working module. If you link it into
-your server, enable the "example-handler" handler for a location, and then
-browse to that location, you will see a display of some of the tracing
-the example module did as the various callbacks were made.
-
-To include the example module in your server run `./configure
---enable-example` in the src directory before running `make`.
-
-To add another module of your own:
-
- A. mkdir src/modules/mymodule
- B. cp src/modules/example/* src/modules/mymodule
- C. Modify the files in the new directory
- D. Build the server as above, with appropriate changes.
-
-To activate the example module, include a block similar to the
-following in your httpd.conf file:
-
- <Location /example-info>
- SetHandler example-handler
- </Location>
-
-As an alternative, you can put the following into a .htaccess file and
-then request the file "test.example" from that location:
-
- AddHandler example-handler .example
-
-After reloading/restarting your server, you should be able to browse
-to this location and see the brief display mentioned earlier.
diff --git a/modules/experimental/cache_storage.c b/modules/experimental/cache_storage.c
deleted file mode 100644
index d3cb540484..0000000000
--- a/modules/experimental/cache_storage.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-#define CORE_PRIVATE
-
-#include "mod_cache.h"
-
-APR_HOOK_STRUCT(
- APR_HOOK_LINK(remove_url)
- APR_HOOK_LINK(create_entity)
- APR_HOOK_LINK(open_entity)
-)
-
-extern APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
-
-extern module AP_MODULE_DECLARE_DATA cache_module;
-
-/* -------------------------------------------------------------- */
-
-/*
- * delete all URL entities from the cache
- *
- */
-int cache_remove_url(request_rec *r, const char *types, char *url)
-{
- const char *next = types;
- const char *type;
- apr_status_t rv;
- char *key;
-
- rv = cache_generate_key(r,r->pool,&key);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- /* for each specified cache type, delete the URL */
- while(next) {
- type = ap_cache_tokstr(r->pool, next, &next);
- cache_run_remove_url(type, key);
- }
- return OK;
-}
-
-
-/*
- * create a new URL entity in the cache
- *
- * It is possible to store more than once entity per URL. This
- * function will always create a new entity, regardless of whether
- * other entities already exist for the same URL.
- *
- * The size of the entity is provided so that a cache module can
- * decide whether or not it wants to cache this particular entity.
- * If the size is unknown, a size of -1 should be set.
- */
-int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t size)
-{
- cache_handle_t *h = apr_pcalloc(r->pool, sizeof(cache_handle_t));
- const char *next = types;
- const char *type;
- char *key;
- apr_status_t rv;
- cache_request_rec *cache = (cache_request_rec *)
- ap_get_module_config(r->request_config, &cache_module);
-
- rv = cache_generate_key(r,r->pool,&key);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- /* for each specified cache type, delete the URL */
- while (next) {
- type = ap_cache_tokstr(r->pool, next, &next);
- switch (rv = cache_run_create_entity(h, r, type, key, size)) {
- case OK: {
- cache->handle = h;
- return OK;
- }
- case DECLINED: {
- continue;
- }
- default: {
- return rv;
- }
- }
- }
- return DECLINED;
-}
-
-/*
- * remove a specific URL entity from the cache
- *
- * The specific entity referenced by the cache_handle is removed
- * from the cache, and the cache_handle is closed.
- */
-/* XXX Don't think we need to pass in request_rec or types ... */
-int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h)
-{
- h->remove_entity(h);
- return 1;
-}
-
-/*
- * select a specific URL entity in the cache
- *
- * It is possible to store more than one entity per URL. Content
- * negotiation is used to select an entity. Once an entity is
- * selected, details of it are stored in the per request
- * config to save time when serving the request later.
- *
- * This function returns OK if successful, DECLINED if no
- * cached entity fits the bill.
- */
-int cache_select_url(request_rec *r, const char *types, char *url)
-{
- const char *next = types;
- const char *type;
- apr_status_t rv;
- cache_info *info;
- char *key;
- cache_request_rec *cache = (cache_request_rec *)
- ap_get_module_config(r->request_config, &cache_module);
-
- rv = cache_generate_key(r,r->pool,&key);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- /* go through the cache types till we get a match */
- cache->handle = apr_palloc(r->pool, sizeof(cache_handle_t));
-
- while (next) {
- type = ap_cache_tokstr(r->pool, next, &next);
- switch ((rv = cache_run_open_entity(cache->handle, r, type, key))) {
- case OK: {
- info = &(cache->handle->cache_obj->info);
- /* XXX:
- * Handle being returned a collection of entities.
- */
-
- /* Has the cache entry expired? */
- if (r->request_time > info->expire)
- cache->fresh = 0;
- else
- cache->fresh = 1;
-
- /*** do content negotiation here */
- return OK;
- }
- case DECLINED: {
- /* try again with next cache type */
- continue;
- }
- default: {
- /* oo-er! an error */
- cache->handle = NULL;
- return rv;
- }
- }
- }
- cache->handle = NULL;
- return DECLINED;
-}
-
-apr_status_t cache_write_entity_headers(cache_handle_t *h,
- request_rec *r,
- cache_info *info)
-{
- return (h->write_headers(h, r, info));
-}
-apr_status_t cache_write_entity_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b)
-{
- return (h->write_body(h, r, b));
-}
-
-apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r)
-{
- apr_status_t rv;
- cache_info *info = &(h->cache_obj->info);
-
- /* Build the header table from info in the info struct */
- rv = h->read_headers(h, r);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- r->content_type = apr_pstrdup(r->pool, info->content_type);
- r->filename = apr_pstrdup(r->pool, info->filename );
-
- return APR_SUCCESS;
-}
-apr_status_t cache_read_entity_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *b)
-{
- return (h->read_body(h, p, b));
-}
-
-apr_status_t cache_generate_key_default( request_rec *r, apr_pool_t*p, char**key )
-{
- *key = apr_pstrdup(p,r->uri);
- return APR_SUCCESS;
-}
-
-APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, create_entity,
- (cache_handle_t *h, request_rec *r, const char *type,
- const char *urlkey, apr_size_t len),
- (h, r, type,urlkey,len),DECLINED)
-APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, open_entity,
- (cache_handle_t *h, request_rec *r, const char *type,
- const char *urlkey),(h,r,type,urlkey),
- DECLINED)
-APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url,
- (const char *type, const char *urlkey),
- (type,urlkey),OK,DECLINED)
-
-
diff --git a/modules/experimental/cache_util.c b/modules/experimental/cache_util.c
deleted file mode 100644
index 18354557a8..0000000000
--- a/modules/experimental/cache_util.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-#define CORE_PRIVATE
-
-#include "mod_cache.h"
-
-
-
-/* -------------------------------------------------------------- */
-
-/* return true if the request is conditional */
-CACHE_DECLARE(int) ap_cache_request_is_conditional(request_rec *r)
-{
- if (apr_table_get(r->headers_in, "If-Match") ||
- apr_table_get(r->headers_in, "If-None-Match") ||
- apr_table_get(r->headers_in, "If-Modified-Since") ||
- apr_table_get(r->headers_in, "If-Unmodified-Since")) {
-
- return 1;
- }
- return 0;
-}
-
-
-/* remove other filters from filter stack */
-CACHE_DECLARE(void) ap_cache_reset_output_filters(request_rec *r)
-{
- ap_filter_t *f = r->output_filters;
-
- while (f) {
- if (!strcasecmp(f->frec->name, "CORE") ||
- !strcasecmp(f->frec->name, "CONTENT_LENGTH") ||
- !strcasecmp(f->frec->name, "HTTP_HEADER")) {
- f = f->next;
- continue;
- }
- else {
- ap_remove_output_filter(f);
- f = f->next;
- }
- }
-}
-
-CACHE_DECLARE(const char *)ap_cache_get_cachetype(request_rec *r,
- cache_server_conf *conf,
- const char *url)
-{
- const char *type = NULL;
- int i;
-
- /* loop through all the cacheenable entries */
- for (i = 0; i < conf->cacheenable->nelts; i++) {
- struct cache_enable *ent =
- (struct cache_enable *)conf->cacheenable->elts;
- const char *thisurl = ent[i].url;
- const char *thistype = ent[i].type;
- if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) {
- if (!type) {
- type = thistype;
- }
- else {
- type = apr_pstrcat(r->pool, type, ",", thistype, NULL);
- }
- }
- }
-
- /* then loop through all the cachedisable entries */
- for (i = 0; i < conf->cachedisable->nelts; i++) {
- struct cache_disable *ent =
- (struct cache_disable *)conf->cachedisable->elts;
- const char *thisurl = ent[i].url;
- if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) {
- type = NULL;
- }
- }
-
- return type;
-}
-
-/*
- * list is a comma-separated list of case-insensitive tokens, with
- * optional whitespace around the tokens.
- * The return returns 1 if the token val is found in the list, or 0
- * otherwise.
- */
-CACHE_DECLARE(int) ap_cache_liststr(const char *list, const char *key, char **val)
-{
- int len, i;
- char *p;
- char valbuf[HUGE_STRING_LEN];
- valbuf[sizeof(valbuf)-1] = 0; /* safety terminating zero */
-
- len = strlen(key);
-
- while (list != NULL) {
- p = strchr((char *) list, ',');
- if (p != NULL) {
- i = p - list;
- do
- p++;
- while (ap_isspace(*p));
- }
- else
- i = strlen(list);
-
- while (i > 0 && ap_isspace(list[i - 1]))
- i--;
- if (i == len && strncasecmp(list, key, len) == 0) {
- if (val) {
- p = strchr((char *) list, ',');
- while (ap_isspace(*list)) {
- list++;
- }
- if ('=' == list[0])
- list++;
- while (ap_isspace(*list)) {
- list++;
- }
- strncpy(valbuf, list, MIN(p-list, sizeof(valbuf)-1));
- *val = valbuf;
- }
- return 1;
- }
- list = p;
- }
- return 0;
-}
-
-/* return each comma separated token, one at a time */
-CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str)
-{
- apr_size_t i;
- const char *s;
-
- s = ap_strchr_c(list, ',');
- if (s != NULL) {
- i = s - list;
- do
- s++;
- while (apr_isspace(*s))
- ; /* noop */
- }
- else
- i = strlen(list);
-
- while (i > 0 && apr_isspace(list[i - 1]))
- i--;
-
- *str = s;
- if (i)
- return apr_pstrndup(p, list, i);
- else
- return NULL;
-}
-
-/*
- * XXX TODO:
- * These functions were lifted from mod_proxy
- * Consider putting them in APR or some other common accessable
- * location.
- */
-/*
- * Converts apr_time_t hex digits to a time integer
- */
-CACHE_DECLARE(apr_time_t) ap_cache_hex2msec(const char *x)
-{
- int i, ch;
- apr_time_t j;
- for (i = 0, j = 0; i < sizeof(j) * 2; i++) {
- ch = x[i];
- j <<= 4;
- if (apr_isdigit(ch))
- j |= ch - '0';
- else if (apr_isupper(ch))
- j |= ch - ('A' - 10);
- else
- j |= ch - ('a' - 10);
- }
- return j;
-}
-
-/*
- * Converts a time integer to apr_time_t hex digits
- */
-CACHE_DECLARE(void) ap_cache_msec2hex(apr_time_t j, char *y)
-{
- int i, ch;
-
- for (i = (sizeof(j) * 2)-1; i >= 0; i--) {
- ch = j & 0xF;
- j >>= 4;
- if (ch >= 10)
- y[i] = ch + ('A' - 10);
- else
- y[i] = ch + '0';
- }
- y[sizeof(j) * 2] = '\0';
-}
-
-static void cache_hash(const char *it, char *val, int ndepth, int nlength)
-{
- apr_md5_ctx_t context;
- unsigned char digest[16];
- char tmp[22];
- int i, k, d;
- unsigned int x;
- static const char enc_table[64] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
-
- apr_md5_init(&context);
- apr_md5_update(&context, (const unsigned char *) it, strlen(it));
- apr_md5_final(digest, &context);
-
- /* encode 128 bits as 22 characters, using a modified uuencoding
- * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is
- * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
- */
- for (i = 0, k = 0; i < 15; i += 3) {
- x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
- tmp[k++] = enc_table[x >> 18];
- tmp[k++] = enc_table[(x >> 12) & 0x3f];
- tmp[k++] = enc_table[(x >> 6) & 0x3f];
- tmp[k++] = enc_table[x & 0x3f];
- }
-
- /* one byte left */
- x = digest[15];
- tmp[k++] = enc_table[x >> 2]; /* use up 6 bits */
- tmp[k++] = enc_table[(x << 4) & 0x3f];
-
- /* now split into directory levels */
- for (i = k = d = 0; d < ndepth; ++d) {
- memcpy(&val[i], &tmp[k], nlength);
- k += nlength;
- val[i + nlength] = '/';
- i += nlength + 1;
- }
- memcpy(&val[i], &tmp[k], 22 - k);
- val[i + 22 - k] = '\0';
-}
-
-CACHE_DECLARE(char *)generate_name(apr_pool_t *p, int dirlevels, int dirlength, const char *name)
-{
- char hashfile[66];
- cache_hash(name, hashfile, dirlevels, dirlength);
- return apr_pstrdup(p, hashfile);
-}
diff --git a/modules/experimental/config.m4 b/modules/experimental/config.m4
deleted file mode 100644
index 9194444872..0000000000
--- a/modules/experimental/config.m4
+++ /dev/null
@@ -1,79 +0,0 @@
-
-APACHE_MODPATH_INIT(experimental)
-
-if test "$ac_cv_ebcdic" = "yes"; then
-# mod_charset_lite can be very useful on an ebcdic system,
-# so include it by default
- APACHE_MODULE(charset_lite, character set translation, , , yes)
-else
- APACHE_MODULE(charset_lite, character set translation, , , no)
-fi
-
-dnl # list of object files for mod_cache
-cache_objs="dnl
-mod_cache.lo dnl
-cache_storage.lo dnl
-cache_util.lo dnl
-"
-APACHE_MODULE(cache, dynamic file caching, $cache_objs, , no)
-APACHE_MODULE(disk_cache, disk caching module, , , no)
-APACHE_MODULE(mem_cache, memory caching module, , , no)
-APACHE_MODULE(example, example and demo module, , , no)
-APACHE_MODULE(ext_filter, external filter module, , , no)
-APACHE_MODULE(case_filter, example uppercase conversion filter, , , no)
-APACHE_MODULE(case_filter_in, example uppercase conversion input filter, , , no)
-
-APACHE_MODULE(deflate, Deflate transfer encoding support, , , no, [
- AC_ARG_WITH(z, APACHE_HELP_STRING(--with-z=DIR,use a specific zlib library),
- [
- if test "x$withval" != "xyes" && test "x$withval" != "x"; then
- ap_zlib_base="$withval"
- fi
- ])
- if test "x$ap_zlib_base" = "x"; then
- AC_MSG_CHECKING([for zlib location])
- AC_CACHE_VAL(ap_cv_zlib,[
- for dir in /usr/local /usr ; do
- if test -d $dir && test -f $dir/include/zlib.h; then
- ap_cv_zlib=$dir
- break
- fi
- done
- ])
- ap_zlib_base=$ap_cv_zlib
- if test "x$ap_zlib_base" = "x"; then
- enable_deflate=no
- AC_MSG_RESULT([not found])
- else
- AC_MSG_RESULT([$ap_zlib_base])
- fi
- fi
- if test "$enable_deflate" != "no"; then
- ap_save_includes=$INCLUDE
- ap_save_ldflags=$LDFLAGS
- ap_save_libs=$LIBS
- ap_save_cppflags=$CPPFLAGS
- if test "$ap_zlib_base" != "/usr"; then
- APR_ADDTO(INCLUDES, [-I${ap_zlib_base}/include])
- dnl put in CPPFLAGS temporarily so that AC_TRY_LINK below will work
- CPPFLAGS="$CPPFLAGS -I${ap_zlib_base}/include"
- APR_ADDTO(LDFLAGS, [-L${ap_zlib_base}/lib])
- if test "x$ap_platform_runtime_link_flag" != "x"; then
- APR_ADDTO(LDFLAGS, [$ap_platform_runtime_link_flag${ap_zlib_base}/lib])
- fi
- fi
- APR_ADDTO(LIBS, [-lz])
- AC_MSG_CHECKING([for zlib library])
- AC_TRY_LINK([#include <zlib.h>], [return Z_OK;],
- [AC_MSG_RESULT(found)
- AC_CHECK_HEADERS(zutil.h)],
- [AC_MSG_RESULT(not found)
- enable_deflate=no
- INCLUDES=$ap_save_includes
- LDFLAGS=$ap_save_ldflags
- LIBS=$ap_save_libs])
- CPPFLAGS=$ap_save_cppflags
- fi
-])
-
-APACHE_MODPATH_FINISH
diff --git a/modules/experimental/mod_auth_ldap.c b/modules/experimental/mod_auth_ldap.c
deleted file mode 100644
index 54bc07ac80..0000000000
--- a/modules/experimental/mod_auth_ldap.c
+++ /dev/null
@@ -1,862 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2001 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- */
-
-/*
- * mod_auth_ldap.c: LDAP authentication module
- *
- * Original code from auth_ldap module for Apache v1.3:
- * Copyright 1998, 1999 Enbridge Pipelines Inc.
- * Copyright 1999-2001 Dave Carrigan
- */
-
-#include <apr_ldap.h>
-#include <apr_strings.h>
-
-#include "ap_config.h"
-#if APR_HAVE_UNISTD_H
-/* for getpid() */
-#include <unistd.h>
-#endif
-#include <ctype.h>
-
-#include "httpd.h"
-#include "http_config.h"
-#include "http_core.h"
-#include "http_log.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "util_ldap.h"
-
-/* per directory configuration */
-typedef struct {
- apr_pool_t *pool; /* Pool that this config is allocated from */
- apr_thread_mutex_t *lock; /* Lock for this config */
- int auth_authoritative; /* Is this auth method the one and only? */
- int enabled; /* Is auth_ldap enabled in this directory? */
-
- /* These parameters are all derived from the AuthLDAPURL directive */
- char *url; /* String representation of the URL */
-
- char *host; /* Name of the LDAP server (or space separated list) */
- int port; /* Port of the LDAP server */
- char *basedn; /* Base DN to do all searches from */
- char *attribute; /* Attribute to search for */
- char **attributes; /* Array of all the attributes to return */
- int scope; /* Scope of the search */
- char *filter; /* Filter to further limit the search */
- deref_options deref; /* how to handle alias dereferening */
- char *binddn; /* DN to bind to server (can be NULL) */
- char *bindpw; /* Password to bind to server (can be NULL) */
-
- int frontpage_hack; /* Hack for frontpage support */
- int user_is_dn; /* If true, connection->user is DN instead of userid */
- int compare_dn_on_server; /* If true, will use server to do DN compare */
-
- int have_ldap_url; /* Set if we have found an LDAP url */
-
- apr_array_header_t *groupattr; /* List of Group attributes */
- int group_attrib_is_dn; /* If true, the group attribute is the DN, otherwise,
- it's the exact string passed by the HTTP client */
-
- int netscapessl; /* True if Netscape SSL is enabled */
- int starttls; /* True if StartTLS is enabled */
-} mod_auth_ldap_config_t;
-
-typedef struct mod_auth_ldap_request_t {
- char *dn; /* The saved dn from a successful search */
- char *user; /* The username provided by the client */
-} mod_auth_ldap_request_t;
-
-/* maximum group elements supported */
-#define GROUPATTR_MAX_ELTS 10
-
-struct mod_auth_ldap_groupattr_entry_t {
- char *name;
-};
-
-module AP_MODULE_DECLARE_DATA auth_ldap_module;
-
-/* function prototypes */
-void mod_auth_ldap_build_filter(char *filtbuf,
- request_rec *r,
- mod_auth_ldap_config_t *sec);
-int mod_auth_ldap_check_user_id(request_rec *r);
-int mod_auth_ldap_auth_checker(request_rec *r);
-void *mod_auth_ldap_create_dir_config(apr_pool_t *p, char *d);
-
-/* ---------------------------------------- */
-
-
-/*
- * Build the search filter, or at least as much of the search filter that
- * will fit in the buffer. We don't worry about the buffer not being able
- * to hold the entire filter. If the buffer wasn't big enough to hold the
- * filter, ldap_search_s will complain, but the only situation where this
- * is likely to happen is if the client sent a really, really long
- * username, most likely as part of an attack.
- *
- * The search filter consists of the filter provided with the URL,
- * combined with a filter made up of the attribute provided with the URL,
- * and the actual username passed by the HTTP client. For example, assume
- * that the LDAP URL is
- *
- * ldap://ldap.airius.com/ou=People, o=Airius?uid??(posixid=*)
- *
- * Further, assume that the userid passed by the client was `userj'. The
- * search filter will be (&(posixid=*)(uid=userj)).
- */
-#define FILTER_LENGTH MAX_STRING_LEN
-void mod_auth_ldap_build_filter(char *filtbuf,
- request_rec *r,
- mod_auth_ldap_config_t *sec)
-{
- char *p, *q, *filtbuf_end;
- /*
- * Create the first part of the filter, which consists of the
- * config-supplied portions.
- */
- apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", sec->filter, sec->attribute);
-
- /*
- * Now add the client-supplied username to the filter, ensuring that any
- * LDAP filter metachars are escaped.
- */
- filtbuf_end = filtbuf + FILTER_LENGTH - 1;
- for (p = r->user, q=filtbuf + strlen(filtbuf);
- *p && q < filtbuf_end; *q++ = *p++) {
- if (strchr("*()\\", *p) != NULL) {
- *q++ = '\\';
- if (q >= filtbuf_end) {
- break;
- }
- }
- }
- *q = '\0';
-
- /*
- * Append the closing parens of the filter, unless doing so would
- * overrun the buffer.
- */
- if (q + 2 <= filtbuf_end)
- strcat(filtbuf, "))");
-}
-
-
-/*
- * Authentication Phase
- * --------------------
- *
- * This phase authenticates the credentials the user has sent with
- * the request (ie the username and password are checked). This is done
- * by making an attempt to bind to the LDAP server using this user's
- * DN and the supplied password.
- *
- */
-int mod_auth_ldap_check_user_id(request_rec *r)
-{
- const char **vals = NULL;
- char filtbuf[FILTER_LENGTH];
- mod_auth_ldap_config_t *sec =
- (mod_auth_ldap_config_t *)ap_get_module_config(r->per_dir_config, &auth_ldap_module);
-
- util_ldap_connection_t *ldc = NULL;
- const char *sent_pw;
- int result = 0;
- const char *dn = NULL;
-
- mod_auth_ldap_request_t *req =
- (mod_auth_ldap_request_t *)apr_pcalloc(r->pool, sizeof(mod_auth_ldap_request_t));
- ap_set_module_config(r->request_config, &auth_ldap_module, req);
-
- if (!sec->enabled) {
- return DECLINED;
- }
-
- /*
- * Basic sanity checks before any LDAP operations even happen.
- */
- if (!sec->have_ldap_url) {
- return DECLINED;
- }
-
- /* There is a good AuthLDAPURL, right? */
- if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->netscapessl, sec->starttls);
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authenticate: no sec->host - weird...?", getpid());
- return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
- }
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authenticate: using URL %s", getpid(), sec->url);
-
- /* Get the password that the client sent */
- if ((result = ap_get_basic_auth_pw(r, &sent_pw))) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authenticate: "
- "ap_get_basic_auth_pw() returns %d", getpid(), result);
- util_ldap_connection_close(ldc);
- return result;
- }
-
- /* build the username filter */
- mod_auth_ldap_build_filter(filtbuf, r, sec);
-
- /* do the user search */
- result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope,
- sec->attributes, filtbuf, sent_pw, &dn, &vals);
- util_ldap_connection_close(ldc);
-
- if (result != LDAP_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authenticate: "
- "user %s authentication failed; URI %s [%s][%s]",
- getpid(), r->user, r->uri, ldc->reason, ldap_err2string(result));
- if (LDAP_INVALID_CREDENTIALS == result) {
- ap_note_basic_auth_failure(r);
- return HTTP_UNAUTHORIZED;
- }
- else {
- return sec->auth_authoritative? HTTP_UNAUTHORIZED: DECLINED;
- }
- }
-
- /* mark the user and DN */
- req->dn = apr_pstrdup(r->pool, dn);
- req->user = r->user;
- if (sec->user_is_dn) {
- r->user = req->dn;
- }
-
- /* add environment variables */
- if (sec->attributes && vals) {
- apr_table_t *e = r->subprocess_env;
- int i = 0;
- while (sec->attributes[i]) {
- char *str = apr_pstrcat(r->pool, "AUTHENTICATE_", sec->attributes[i], NULL);
- int j = 13;
- while (str[j]) {
- if (str[j] >= 'a' && str[j] <= 'z') {
- str[j] = str[j] - ('a' - 'A');
- }
- j++;
- }
- apr_table_setn(e, str, vals[i]);
- i++;
- }
- }
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authenticate: accepting %s", getpid(), r->user);
-
- return OK;
-}
-
-
-/*
- * Authorisation Phase
- * -------------------
- *
- * After checking whether the username and password are correct, we need
- * to check whether that user is authorised to view this resource. The
- * require directive is used to do this:
- *
- * require valid-user Any authenticated is allowed in.
- * require user <username> This particular user is allowed in.
- * require group <groupname> The user must be a member of this group
- * in order to be allowed in.
- * require dn <dn> The user must have the following DN in the
- * LDAP tree to be let in.
- *
- */
-int mod_auth_ldap_auth_checker(request_rec *r)
-{
- int result = 0;
- mod_auth_ldap_request_t *req =
- (mod_auth_ldap_request_t *)ap_get_module_config(r->request_config,
- &auth_ldap_module);
- mod_auth_ldap_config_t *sec =
- (mod_auth_ldap_config_t *)ap_get_module_config(r->per_dir_config,
- &auth_ldap_module);
-
- util_ldap_connection_t *ldc = NULL;
- int m = r->method_number;
-
- const apr_array_header_t *reqs_arr = ap_requires(r);
- require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
-
- register int x;
- const char *t;
- char *w;
- int method_restricted = 0;
-
- if (!sec->enabled) {
- return DECLINED;
- }
-
- if (!sec->have_ldap_url) {
- return DECLINED;
- }
-
- if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->netscapessl, sec->starttls);
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: no sec->host - weird...?", getpid());
- return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
- }
-
- /*
- * If there are no elements in the group attribute array, the default should be
- * member and uniquemember; populate the array now.
- */
- if (sec->groupattr->nelts == 0) {
- struct mod_auth_ldap_groupattr_entry_t *grp;
- apr_thread_mutex_lock(sec->lock);
- grp = apr_array_push(sec->groupattr);
- grp->name = "member";
- grp = apr_array_push(sec->groupattr);
- grp->name = "uniquemember";
- apr_thread_mutex_unlock(sec->lock);
- }
-
- if (!reqs_arr) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: no requirements array", getpid());
- return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
- }
-
- /* Loop through the requirements array until there's no elements
- * left, or something causes a return from inside the loop */
- for(x=0; x < reqs_arr->nelts; x++) {
- if (! (reqs[x].method_mask & (1 << m))) {
- continue;
- }
- method_restricted = 1;
-
- t = reqs[x].requirement;
- w = ap_getword(r->pool, &t, ' ');
-
- if (strcmp(w, "valid-user") == 0) {
- /*
- * Valid user will always be true if we authenticated with ldap,
- * but when using front page, valid user should only be true if
- * he exists in the frontpage password file. This hack will get
- * auth_ldap to look up the user in the the pw file to really be
- * sure that he's valid. Naturally, it requires mod_auth to be
- * compiled in, but if mod_auth wasn't in there, then the need
- * for this hack wouldn't exist anyway.
- */
- if (sec->frontpage_hack) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "deferring authorisation to mod_auth (FP Hack)",
- getpid());
- return OK;
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "successful authorisation because user "
- "is valid-user", getpid());
- return OK;
- }
- }
- else if (strcmp(w, "user") == 0) {
- if (req->dn == NULL || strlen(req->dn) == 0) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require user: user's DN has not been defined; failing authorisation",
- getpid());
- return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
- }
- /*
- * First do a whole-line compare, in case it's something like
- * require user Babs Jensen
- */
- result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, t);
- switch(result) {
- case LDAP_COMPARE_TRUE: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require user: authorisation successful", getpid());
- return OK;
- }
- default: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: require user: "
- "authorisation failed [%s][%s]", getpid(),
- ldc->reason, ldap_err2string(result));
- }
- }
- /*
- * Now break apart the line and compare each word on it
- */
- while (t[0]) {
- w = ap_getword_conf(r->pool, &t);
- result = util_ldap_cache_compare(r, ldc, sec->url, req->dn, sec->attribute, w);
- switch(result) {
- case LDAP_COMPARE_TRUE: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require user: authorisation successful", getpid());
- return OK;
- }
- default: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require user: authorisation failed [%s][%s]",
- getpid(), ldc->reason, ldap_err2string(result));
- }
- }
- }
- }
- else if (strcmp(w, "dn") == 0) {
- if (req->dn == NULL || strlen(req->dn) == 0) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require dn: user's DN has not been defined; failing authorisation",
- getpid());
- return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
- }
-
- result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, t, sec->compare_dn_on_server);
- switch(result) {
- case LDAP_COMPARE_TRUE: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require dn: authorisation successful", getpid());
- return OK;
- }
- default: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: "
- "require dn: LDAP error [%s][%s]",
- getpid(), ldc->reason, ldap_err2string(result));
- }
- }
- }
- else if (strcmp(w, "group") == 0) {
- struct mod_auth_ldap_groupattr_entry_t *ent = (struct mod_auth_ldap_groupattr_entry_t *) sec->groupattr->elts;
- int i;
-
- if (sec->group_attrib_is_dn) {
- if (req->dn == NULL || strlen(req->dn) == 0) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: require group: user's DN has not been defined; failing authorisation",
- getpid());
- return sec->auth_authoritative? HTTP_UNAUTHORIZED : DECLINED;
- }
- }
- else {
- if (req->user == NULL || strlen(req->user) == 0) {
- /* We weren't called in the authentication phase, so we didn't have a
- * chance to set the user field. Do so now. */
- req->user = r->user;
- }
- }
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: require group: testing for group membership in `%s'",
- getpid(), t);
-
- for (i = 0; i < sec->groupattr->nelts; i++) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: require group: testing for %s: %s (%s)", getpid(),
- ent[i].name, sec->group_attrib_is_dn ? req->dn : req->user, t);
-
- result = util_ldap_cache_compare(r, ldc, sec->url, t, ent[i].name,
- sec->group_attrib_is_dn ? req->dn : req->user);
- switch(result) {
- case LDAP_COMPARE_TRUE: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: require group: "
- "authorisation successful (attribute %s) [%s][%s]",
- getpid(), ent[i].name, ldc->reason, ldap_err2string(result));
- return OK;
- }
- default: {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: require group: "
- "authorisation failed [%s][%s]",
- getpid(), ldc->reason, ldap_err2string(result));
- }
- }
- }
- }
- }
-
- if (!method_restricted) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: agreeing because non-restricted",
- getpid());
- return OK;
- }
-
- if (!sec->auth_authoritative) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: declining to authorise", getpid());
- return DECLINED;
- }
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "[%d] auth_ldap authorise: authorisation denied", getpid());
- ap_note_basic_auth_failure (r);
-
- return HTTP_UNAUTHORIZED;
-}
-
-
-/* ---------------------------------------- */
-/* config directives */
-
-
-void *mod_auth_ldap_create_dir_config(apr_pool_t *p, char *d)
-{
- mod_auth_ldap_config_t *sec =
- (mod_auth_ldap_config_t *)apr_pcalloc(p, sizeof(mod_auth_ldap_config_t));
-
- sec->pool = p;
- apr_thread_mutex_create(&sec->lock, APR_THREAD_MUTEX_DEFAULT, p);
- sec->auth_authoritative = 1;
- sec->enabled = 1;
- sec->groupattr = apr_array_make(p, GROUPATTR_MAX_ELTS,
- sizeof(struct mod_auth_ldap_groupattr_entry_t));
-
- sec->have_ldap_url = 0;
- sec->url = "";
- sec->host = NULL;
- sec->binddn = NULL;
- sec->bindpw = NULL;
- sec->deref = always;
- sec->group_attrib_is_dn = 1;
-
- sec->frontpage_hack = 0;
- sec->netscapessl = 0;
- sec->starttls = 0;
-
- sec->user_is_dn = 0;
- sec->compare_dn_on_server = 0;
-
- return sec;
-}
-
-/*
- * Use the ldap url parsing routines to break up the ldap url into
- * host and port.
- */
-static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
- void *config,
- const char *url)
-{
- int result;
- LDAPURLDesc *urld;
-
- mod_auth_ldap_config_t *sec = config;
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: `%s'",
- getpid(), url);
-
- result = ldap_url_parse(url, &(urld));
- if (result != LDAP_SUCCESS) {
- switch (result) {
- case LDAP_URL_ERR_NOTLDAP:
- return "LDAP URL does not begin with ldap://";
- case LDAP_URL_ERR_NODN:
- return "LDAP URL does not have a DN";
- case LDAP_URL_ERR_BADSCOPE:
- return "LDAP URL has an invalid scope";
- case LDAP_URL_ERR_MEM:
- return "Out of memory parsing LDAP URL";
- default:
- return "Could not parse LDAP URL";
- }
- }
- sec->url = apr_pstrdup(cmd->pool, url);
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: Host: %s", getpid(), urld->lud_host);
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: Port: %d", getpid(), urld->lud_port);
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: DN: %s", getpid(), urld->lud_dn);
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: attrib: %s", getpid(), urld->lud_attrs? urld->lud_attrs[0] : "(null)");
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: scope: %s", getpid(),
- (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" :
- urld->lud_scope == LDAP_SCOPE_BASE? "base" :
- urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"));
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap url parse: filter: %s", getpid(), urld->lud_filter);
-
- /* Set all the values, or at least some sane defaults */
- if (sec->host) {
- char *p = apr_palloc(cmd->pool, strlen(sec->host) + strlen(urld->lud_host) + 2);
- strcpy(p, urld->lud_host);
- strcat(p, " ");
- strcat(p, sec->host);
- sec->host = p;
- }
- else {
- sec->host = urld->lud_host? apr_pstrdup(cmd->pool, urld->lud_host) : "localhost";
- }
- sec->basedn = urld->lud_dn? apr_pstrdup(cmd->pool, urld->lud_dn) : "";
- if (urld->lud_attrs && urld->lud_attrs[0]) {
- int i = 1;
- while (urld->lud_attrs[i]) {
- i++;
- }
- sec->attributes = apr_pcalloc(cmd->pool, sizeof(char *) * (i+1));
- i = 0;
- while (urld->lud_attrs[i]) {
- sec->attributes[i] = apr_pstrdup(cmd->pool, urld->lud_attrs[i]);
- i++;
- }
- sec->attribute = sec->attributes[0];
- }
- else {
- sec->attribute = "uid";
- }
-
- sec->scope = urld->lud_scope == LDAP_SCOPE_ONELEVEL ?
- LDAP_SCOPE_ONELEVEL : LDAP_SCOPE_SUBTREE;
-
- if (urld->lud_filter) {
- if (urld->lud_filter[0] == '(') {
- /*
- * Get rid of the surrounding parens; later on when generating the
- * filter, they'll be put back.
- */
- sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter+1);
- sec->filter[strlen(sec->filter)-1] = '\0';
- }
- else {
- sec->filter = apr_pstrdup(cmd->pool, urld->lud_filter);
- }
- }
- else {
- sec->filter = "objectclass=*";
- }
- if (strncmp(url, "ldaps", 5) == 0) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap parse url: requesting secure LDAP", getpid());
-#ifdef APU_HAS_LDAP_STARTTLS
- sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
- sec->starttls = 1;
-#else
-#ifdef APU_HAS_LDAP_NETSCAPE_SSL
- sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
- sec->netscapessl = 1;
-#else
- return "Secure LDAP (ldaps://) not supported. Rebuild APR-Util";
-#endif
-#endif
- }
- else {
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
- cmd->server, "[%d] auth_ldap parse url: not requesting secure LDAP", getpid());
- sec->netscapessl = 0;
- sec->starttls = 0;
- sec->port = urld->lud_port? urld->lud_port : LDAP_PORT;
- }
-
- sec->have_ldap_url = 1;
- ldap_free_urldesc(urld);
- return NULL;
-}
-
-static const char *mod_auth_ldap_set_deref(cmd_parms *cmd, void *config, const char *arg)
-{
- mod_auth_ldap_config_t *sec = config;
-
- if (strcmp(arg, "never") == 0 || strcasecmp(arg, "off") == 0) {
- sec->deref = never;
- }
- else if (strcmp(arg, "searching") == 0) {
- sec->deref = searching;
- }
- else if (strcmp(arg, "finding") == 0) {
- sec->deref = finding;
- }
- else if (strcmp(arg, "always") == 0 || strcasecmp(arg, "on") == 0) {
- sec->deref = always;
- }
- else {
- return "Unrecognized value for AuthLDAPAliasDereference directive";
- }
- return NULL;
-}
-
-static const char *mod_auth_ldap_add_group_attribute(cmd_parms *cmd, void *config, const char *arg)
-{
- struct mod_auth_ldap_groupattr_entry_t *new;
-
- mod_auth_ldap_config_t *sec = config;
-
- if (sec->groupattr->nelts > GROUPATTR_MAX_ELTS)
- return "Too many AuthLDAPGroupAttribute directives";
-
- new = apr_array_push(sec->groupattr);
- new->name = apr_pstrdup(cmd->pool, arg);
-
- return NULL;
-}
-
-command_rec mod_auth_ldap_cmds[] = {
- AP_INIT_TAKE1("AuthLDAPURL", mod_auth_ldap_parse_url, NULL, OR_AUTHCFG,
- "URL to define LDAP connection. This should be an RFC 2255 complaint\n"
- "URL of the form ldap://host[:port]/basedn[?attrib[?scope[?filter]]].\n"
- "<ul>\n"
- "<li>Host is the name of the LDAP server. Use a space separated list of hosts \n"
- "to specify redundant servers.\n"
- "<li>Port is optional, and specifies the port to connect to.\n"
- "<li>basedn specifies the base DN to start searches from\n"
- "<li>Attrib specifies what attribute to search for in the directory. If not "
- "provided, it defaults to <b>uid</b>.\n"
- "<li>Scope is the scope of the search, and can be either <b>sub</b> or "
- "<b>one</b>. If not provided, the default is <b>sub</b>.\n"
- "<li>Filter is a filter to use in the search. If not provided, "
- "defaults to <b>(objectClass=*)</b>.\n"
- "</ul>\n"
- "Searches are performed using the attribute and the filter combined. "
- "For example, assume that the\n"
- "LDAP URL is <b>ldap://ldap.airius.com/ou=People, o=Airius?uid?sub?(posixid=*)</b>. "
- "Searches will\n"
- "be done using the filter <b>(&((posixid=*))(uid=<i>username</i>))</b>, "
- "where <i>username</i>\n"
- "is the user name passed by the HTTP client. The search will be a subtree "
- "search on the branch <b>ou=People, o=Airius</b>."),
-
- AP_INIT_TAKE1("AuthLDAPBindDN", ap_set_string_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, binddn), OR_AUTHCFG,
- "DN to use to bind to LDAP server. If not provided, will do an anonymous bind."),
-
- AP_INIT_TAKE1("AuthLDAPBindPassword", ap_set_string_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, bindpw), OR_AUTHCFG,
- "Password to use to bind to LDAP server. If not provided, will do an anonymous bind."),
-
- AP_INIT_FLAG("AuthLDAPRemoteUserIsDN", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, user_is_dn), OR_AUTHCFG,
- "Set to 'on' to set the REMOTE_USER environment variable to be the full "
- "DN of the remote user. By default, this is set to off, meaning that "
- "the REMOTE_USER variable will contain whatever value the remote user sent."),
-
- AP_INIT_FLAG("AuthLDAPAuthoritative", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, auth_authoritative), OR_AUTHCFG,
- "Set to 'off' to allow access control to be passed along to lower modules if "
- "the UserID and/or group is not known to this module"),
-
- AP_INIT_FLAG("AuthLDAPCompareDNOnServer", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, compare_dn_on_server), OR_AUTHCFG,
- "Set to 'on' to force auth_ldap to do DN compares (for the \"require dn\" "
- "directive) using the server, and set it 'off' to do the compares locally "
- "(at the expense of possible false matches). See the documentation for "
- "a complete description of this option."),
-
- AP_INIT_ITERATE("AuthLDAPGroupAttribute", mod_auth_ldap_add_group_attribute, NULL, OR_AUTHCFG,
- "A list of attributes used to define group membership - defaults to "
- "member and uniquemember"),
-
- AP_INIT_FLAG("AuthLDAPGroupAttributeIsDN", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, group_attrib_is_dn), OR_AUTHCFG,
- "If set to 'on', auth_ldap uses the DN that is retrieved from the server for"
- "subsequent group comparisons. If set to 'off', auth_ldap uses the string"
- "provided by the client directly. Defaults to 'on'."),
-
- AP_INIT_TAKE1("AuthLDAPDereferenceAliases", mod_auth_ldap_set_deref, NULL, OR_AUTHCFG,
- "Determines how aliases are handled during a search. Can bo one of the"
- "values \"never\", \"searching\", \"finding\", or \"always\". "
- "Defaults to always."),
-
- AP_INIT_FLAG("AuthLDAPEnabled", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, enabled), OR_AUTHCFG,
- "Set to off to disable auth_ldap, even if it's been enabled in a higher tree"),
-
- AP_INIT_FLAG("AuthLDAPFrontPageHack", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, frontpage_hack), OR_AUTHCFG,
- "Set to 'on' to support Microsoft FrontPage"),
-
-#ifdef APU_HAS_LDAP_STARTTLS
- AP_INIT_FLAG("AuthLDAPStartTLS", ap_set_flag_slot,
- (void *)APR_XtOffsetOf(mod_auth_ldap_config_t, starttls), OR_AUTHCFG,
- "Set to 'on' to start TLS after connecting to the LDAP server."),
-#endif /* APU_HAS_LDAP_STARTTLS */
-
- {NULL}
-};
-
-static void mod_auth_ldap_register_hooks(apr_pool_t *p)
-{
- ap_hook_check_user_id(mod_auth_ldap_check_user_id, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_auth_checker(mod_auth_ldap_auth_checker, NULL, NULL, APR_HOOK_MIDDLE);
-}
-
-module auth_ldap_module = {
- STANDARD20_MODULE_STUFF,
- mod_auth_ldap_create_dir_config, /* dir config creater */
- NULL, /* dir merger --- default is to override */
- NULL, /* server config */
- NULL, /* merge server config */
- mod_auth_ldap_cmds, /* command table */
- mod_auth_ldap_register_hooks, /* set up request processing hooks */
-};
diff --git a/modules/experimental/mod_auth_ldap.def b/modules/experimental/mod_auth_ldap.def
deleted file mode 100644
index 599636fb49..0000000000
--- a/modules/experimental/mod_auth_ldap.def
+++ /dev/null
@@ -1,6 +0,0 @@
-IMPORT util_ldap_connection_find
-IMPORT util_ldap_connection_close
-IMPORT util_ldap_cache_checkuserid
-IMPORT util_ldap_cache_compare
-IMPORT util_ldap_cache_comparedn
-EXPORT auth_ldap_module
diff --git a/modules/experimental/mod_cache.c b/modules/experimental/mod_cache.c
deleted file mode 100644
index 964950fd67..0000000000
--- a/modules/experimental/mod_cache.c
+++ /dev/null
@@ -1,995 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-#define CORE_PRIVATE
-
-#include "mod_cache.h"
-
-module AP_MODULE_DECLARE_DATA cache_module;
-APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
-
-/* -------------------------------------------------------------- */
-
-
-
-/*
- * CACHE handler
- * -------------
- *
- * Can we deliver this request from the cache?
- * If yes:
- * deliver the content by installing the CACHE_OUT filter.
- * If no:
- * check whether we're allowed to try cache it
- * If yes:
- * add CACHE_IN filter
- * If No:
- * oh well.
- */
-
-static int cache_url_handler(request_rec *r)
-{
- apr_status_t rv;
- const char *cc_in, *pragma, *auth;
- apr_uri_t uri = r->parsed_uri;
- char *url = r->unparsed_uri;
- apr_size_t urllen;
- char *path = uri.path;
- const char *types;
- cache_info *info = NULL;
- cache_request_rec *cache;
- cache_server_conf *conf =
- (cache_server_conf *) ap_get_module_config(r->server->module_config,
- &cache_module);
-
- /* we don't handle anything but GET */
- if (r->method_number != M_GET) return DECLINED;
-
- /*
- * Which cache module (if any) should handle this request?
- */
- if (!(types = ap_cache_get_cachetype(r, conf, path))) {
- return DECLINED;
- }
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: URL %s is being handled by %s", path, types);
-
- urllen = strlen(url);
- if (urllen > MAX_URL_LENGTH) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: URL exceeds length threshold: %s", url);
- return DECLINED;
- }
- /* DECLINE urls ending in / */
- if (url[urllen-1] == '/') {
- return DECLINED;
- }
-
- /* make space for the per request config */
- cache = (cache_request_rec *) ap_get_module_config(r->request_config,
- &cache_module);
- if (!cache) {
- cache = ap_pcalloc(r->pool, sizeof(cache_request_rec));
- ap_set_module_config(r->request_config, &cache_module, cache);
- }
-
- /* save away the type */
- cache->types = types;
-
- /*
- * Are we allowed to serve cached info at all?
- */
-
- /* find certain cache controlling headers */
- cc_in = apr_table_get(r->headers_in, "Cache-Control");
- pragma = apr_table_get(r->headers_in, "Pragma");
- auth = apr_table_get(r->headers_in, "Authorization");
-
- /* first things first - does the request allow us to return
- * cached information at all? If not, just decline the request.
- *
- * Note that there is a big difference between not being allowed
- * to cache a request (no-store) and not being allowed to return
- * a cached request without revalidation (max-age=0).
- *
- * Caching is forbidden under the following circumstances:
- *
- * - RFC2616 14.9.2 Cache-Control: no-store
- * - Pragma: no-cache
- * - Any requests requiring authorization.
- * - Any URLs whose length exceeds MAX_URL_LENGTH
- * - TODO: Make MAX_URL_LENGTH a config directive?
- */
- if (conf->ignorecachecontrol_set == 1 && conf->ignorecachecontrol == 1 && auth == NULL) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "incoming request is asking for a uncached version of %s, but we know better and are ignoring it", url);
- }
- else {
- if (ap_cache_liststr(cc_in, "no-store", NULL) ||
- ap_cache_liststr(pragma, "no-cache", NULL) || (auth != NULL)) {
- /* delete the previously cached file */
- cache_remove_url(r, cache->types, url);
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: no-store forbids caching of %s", url);
- return DECLINED;
- }
- }
-
- /*
- * Try serve this request from the cache.
- *
- * If no existing cache file
- * add cache_in filter
- * If stale cache file
- * If conditional request
- * add cache_in filter
- * If non-conditional request
- * fudge response into a conditional
- * add cache_conditional filter
- * If fresh cache file
- * clear filter stack
- * add cache_out filter
- */
-
- rv = cache_select_url(r, cache->types, url);
- if (DECLINED == rv) {
- /* no existing cache file */
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: no cache - add cache_in filter and DECLINE");
- /* add cache_in filter to cache this request */
- ap_add_output_filter("CACHE_IN", NULL, r, r->connection);
- /* return DECLINED */
- return DECLINED;
- }
- else if (OK == rv) {
- /* cache file exists */
- if (cache->fresh) {
- apr_bucket_brigade *out;
-
- /* fresh data available */
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: fresh cache - add cache_out filter and "
- "handle request");
-
- /* We are in the quick handler hook, which means that no output
- * filters have been set. So lets run the insert_filter hook.
- * XXX - Should we be inserting filters in the output stream
- * for proxy requests? Certainly we need the core filters
- * (byterange, chunking, etc.). I can also see the need to
- * conditionally insert tag processing filters (e.g. INCLUDES).
- */
- ap_run_insert_filter(r);
-
- /* Now add the cache_out filter. cache_out is a FTYPE_CONTENT
- * which means it will be inserted first in the stream, which
- * is exactly what we need.
- */
- ap_add_output_filter("CACHE_OUT", NULL, r, r->connection);
-
- /* kick off the filter stack */
- out = apr_brigade_create(r->pool);
- if (APR_SUCCESS != (rv = ap_pass_brigade(r->output_filters, out))) {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
- "cache: error returned while trying to return %s "
- "cached data",
- cache->type);
- return rv;
- }
- return OK;
- }
- else {
- /* stale data available */
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: stale cache - test conditional");
- /* if conditional request */
- if (ap_cache_request_is_conditional(r)) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0,
- r->server,
- "cache: conditional - add cache_in filter and "
- "DECLINE");
- /* add cache_in filter */
- ap_add_output_filter("CACHE_IN", NULL, r, r->connection);
- /* return DECLINED */
- return DECLINED;
- }
- /* else if non-conditional request */
- else {
- /* fudge response into a conditional */
- if (info && info->etag) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0,
- r->server,
- "cache: nonconditional - fudge conditional "
- "by etag");
- /* if we have a cached etag */
- apr_table_set(r->headers_in, "If-None-Match", info->etag);
- }
- else if (info && info->lastmods) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0,
- r->server,
- "cache: nonconditional - fudge conditional "
- "by lastmod");
- /* if we have a cached IMS */
- apr_table_set(r->headers_in,
- "If-Modified-Since",
- info->lastmods);
- }
- else {
- /* something else - pretend there was no cache */
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0,
- r->server,
- "cache: nonconditional - no cached "
- "etag/lastmods - add cache_in and DECLINE");
- /* add cache_in filter to cache this request */
- ap_add_output_filter("CACHE_IN", NULL, r, r->connection);
- /* return DECLINED */
- return DECLINED;
- }
- /* add cache_conditional filter */
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0,
- r->server,
- "cache: nonconditional - add cache_conditional and"
- " DECLINE");
- ap_add_output_filter("CACHE_CONDITIONAL",
- NULL,
- r,
- r->connection);
- /* return DECLINED */
- return DECLINED;
- }
- }
- }
- else {
- /* error */
- ap_log_error(APLOG_MARK, APLOG_ERR, rv,
- r->server,
- "cache: error returned while checking for cached file by "
- "%s cache",
- cache->type);
- return DECLINED;
- }
-}
-
-/*
- * CACHE_OUT filter
- * ----------------
- *
- * Deliver cached content (headers and body) up the stack.
- */
-static int cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- request_rec *r = f->r;
- cache_request_rec *cache =
- (cache_request_rec *) ap_get_module_config(r->request_config,
- &cache_module);
-
- if (!cache) {
- /* user likely configured CACHE_OUT manually; they should use mod_cache
- * configuration to do that */
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "CACHE_OUT enabled unexpectedly");
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: running CACHE_OUT filter");
-
- /* TODO: Handle getting errors on either of these calls */
- cache_read_entity_headers(cache->handle, r);
- cache_read_entity_body(cache->handle, r->pool, bb);
-
- /* This filter is done once it has served up its content */
- ap_remove_output_filter(f);
-
- ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, 0, r->server,
- "cached version of %s being served", r->uri);
- return ap_pass_brigade(f->next, bb);
-}
-
-
-/*
- * CACHE_CONDITIONAL filter
- * ------------------------
- *
- * Decide whether or not cached content should be delivered
- * based on our fudged conditional request.
- * If response HTTP_NOT_MODIFIED
- * replace ourselves with cache_out filter
- * Otherwise
- * replace ourselves with cache_in filter
- */
-
-static int cache_conditional_filter(ap_filter_t *f, apr_bucket_brigade *in)
-{
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, f->r->server,
- "cache: running CACHE_CONDITIONAL filter");
-
- if (f->r->status == HTTP_NOT_MODIFIED) {
- /* replace ourselves with CACHE_OUT filter */
- ap_add_output_filter("CACHE_OUT", NULL, f->r, f->r->connection);
- }
- else {
- /* replace ourselves with CACHE_IN filter */
- ap_add_output_filter("CACHE_IN", NULL, f->r, f->r->connection);
- }
- ap_remove_output_filter(f);
-
- return ap_pass_brigade(f->next, in);
-}
-
-
-/*
- * CACHE_IN filter
- * ---------------
- *
- * Decide whether or not this content should be cached.
- * If we decide no it should:
- * remove the filter from the chain
- * If we decide yes it should:
- * pass the data to the storage manager
- * pass the data to the next filter (the network)
- *
- */
-
-static int cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in)
-{
- int rv;
- request_rec *r = f->r;
- char *url = r->unparsed_uri;
- const char *cc_out = ap_table_get(r->headers_out, "Cache-Control");
- const char *exps, *lastmods, *dates, *etag;
- apr_time_t exp, date, lastmod, now;
- apr_size_t size;
- cache_info *info;
- void *sconf = r->server->module_config;
- cache_server_conf *conf =
- (cache_server_conf *) ap_get_module_config(sconf, &cache_module);
- void *scache = r->request_config;
- cache_request_rec *cache =
- (cache_request_rec *) ap_get_module_config(scache, &cache_module);
-
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, f->r->server,
- "cache: running CACHE_IN filter");
-
- /* check first whether running this filter has any point or not */
- if(r->no_cache) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, in);
- }
-
- /* make space for the per request config
- * We hit this code path when CACHE_IN has been installed by someone
- * other than the cache handler
- */
- if (!cache) {
- cache = ap_pcalloc(r->pool, sizeof(cache_request_rec));
- ap_set_module_config(r->request_config, &cache_module, cache);
- }
-
- /*
- * Pass Data to Cache
- * ------------------
- * This section passes the brigades into the cache modules, but only
- * if the setup section (see below) is complete.
- */
-
- /* have we already run the cachability check and set up the cached file
- * handle?
- */
- if (cache->in_checked) {
- /* pass the brigades into the cache, then pass them
- * up the filter stack
- */
- rv = cache_write_entity_body(cache->handle, r, in);
- if (rv != APR_SUCCESS) {
- ap_remove_output_filter(f);
- }
- return ap_pass_brigade(f->next, in);
- }
-
- /*
- * Setup Data in Cache
- * -------------------
- * This section opens the cache entity and sets various caching parameters,
- * and decides whether this URL should be cached at all. This section is
- * run before the above section.
- */
- info = ap_pcalloc(r->pool, sizeof(cache_info));
-
- /* read expiry date; if a bad date, then leave it so the client can
- * read it
- */
- exps = ap_table_get(r->headers_out, "Expires");
- if (exps != NULL) {
- if (APR_DATE_BAD == (exp = apr_date_parse_http(exps))) {
- exps = NULL;
- }
- }
- else {
- exp = APR_DATE_BAD;
- }
-
- /* read the last-modified date; if the date is bad, then delete it */
- lastmods = ap_table_get(r->headers_out, "Last-Modified");
- if (lastmods != NULL) {
- if (APR_DATE_BAD == (lastmod = apr_date_parse_http(lastmods))) {
- lastmods = NULL;
- }
- }
- else {
- lastmod = APR_DATE_BAD;
- }
-
- /* read the etag from the entity */
- etag = ap_table_get(r->headers_out, "Etag");
-
- /*
- * 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 */
- (exps != NULL && exp == APR_DATE_BAD) ||
-
- /* 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 && (NULL == cache->handle)) ||
-
- /* 200 OK response from HTTP/1.0 and up without a Last-Modified header/Etag
- */
- /* XXX mod-include clears last_modified/expires/etags - this is why we have
- * a optional function for a key-gen ;-)
- */
- (r->status == HTTP_OK && lastmods == NULL && etag == NULL
- && (conf->no_last_mod_ignore ==0)) ||
-
- /* 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_cache_liststr(cc_out, "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_cache_liststr(cc_out, "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_cache_liststr(cc_out, "s-maxage", NULL) ||
- ap_cache_liststr(cc_out, "must-revalidate", NULL) ||
- ap_cache_liststr(cc_out, "public", NULL))
- ) ||
-
- /* or we've been asked not to cache it above */
- r->no_cache) {
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: response is not cachable");
-
- /* remove this object from the cache
- * BillS Asks.. Why do we need to make this call to remove_url?
- * leave it in for now..
- */
- cache_remove_url(r, cache->types, url);
-
- /* remove this filter from the chain */
- ap_remove_output_filter(f);
-
- /* ship the data up the stack */
- return ap_pass_brigade(f->next, in);
- }
- cache->in_checked = 1;
-
- /* Set the content length if known. We almost certainly do NOT want to
- * cache streams with unknown content lengths in the in-memory cache.
- * Streams with unknown content length should be first cached in the
- * file system. If they are withing acceptable limits, then they can be
- * moved to the in-memory cache.
- */
- {
- const char* cl;
- cl = apr_table_get(r->headers_out, "Content-Length");
- if (cl) {
- size = atol(cl);
- }
- else {
-
- /* if we don't get the content-length, see if we have all the
- * buckets and use their length to calculate the size
- */
- apr_bucket *e;
- int all_buckets_here=0;
- size=0;
- APR_BRIGADE_FOREACH(e, in) {
- if (APR_BUCKET_IS_EOS(e)) {
- all_buckets_here=1;
- break;
- }
- if (APR_BUCKET_IS_FLUSH(e)) {
- continue;
- }
- if (e->length < 0) {
- break;
- }
- size += e->length;
- }
-
- if (!all_buckets_here) {
- size = -1;
- }
- }
- }
-
- /* It's safe to cache the response.
- *
- * There are two possiblities at this point:
- * - cache->handle == NULL. In this case there is no previously
- * cached entity anywhere on the system. We must create a brand
- * new entity and store the response in it.
- * - cache->handle != NULL. In this case there is a stale
- * entity in the system which needs to be replaced by new
- * content (unless the result was 304 Not Modified, which means
- * the cached entity is actually fresh, and we should update
- * the headers).
- */
- /* no cache handle, create a new entity */
- if (!cache->handle) {
- rv = cache_create_entity(r, cache->types, url, size);
- }
- /* pre-existing cache handle and 304, make entity fresh */
- else if (r->status == HTTP_NOT_MODIFIED) {
- /* update headers */
-
- /* remove this filter ??? */
-
- /* XXX is this right? we must set rv to something other than OK
- * in this path
- */
- rv = HTTP_NOT_MODIFIED;
- }
- /* pre-existing cache handle and new entity, replace entity with this one */
- else {
- cache_remove_entity(r, cache->types, cache->handle);
- rv = cache_create_entity(r, cache->types, url, size);
- }
-
- if (rv != OK) {
- /* Caching layer declined the opportunity to cache the response */
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, in);
- }
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: Caching url: %s", url);
-
- /*
- * 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 */
- dates = ap_table_get(r->headers_out, "Date");
- if (dates != NULL)
- info->date = apr_date_parse_http(dates);
- else
- info->date = APR_DATE_BAD;
-
- now = apr_time_now();
- if (info->date == APR_DATE_BAD) { /* No, or bad date */
- char *dates;
- /* no date header! */
- /* add one; N.B. use the time _now_ rather than when we were checking
- * the cache
- */
- date = now;
- dates = apr_pcalloc(r->pool, MAX_STRING_LEN);
- apr_rfc822_date(dates, now);
- ap_table_set(r->headers_out, "Date", dates);
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server,
- "cache: Added date header");
- info->date = date;
- }
- else {
- date = info->date;
- }
-
- /* set response_time for HTTP/1.1 age calculations */
- info->response_time = now;
-
- /* get the request time */
- info->request_time = r->request_time;
-
- /* check last-modified date */
- /* XXX FIXME we're referencing date on a path where we didn't set it */
- if (lastmod != APR_DATE_BAD && lastmod > date)
- {
- /* if its in the future, then replace by date */
- lastmod = date;
- lastmods = dates;
- ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0,
- r->server,
- "cache: Last modified is in the future, "
- "replacing with now");
- }
- info->lastmod = lastmod;
-
- /* if no expiry date then
- * if lastmod
- * expiry date = now + min((date - lastmod) * factor, maxexpire)
- * else
- * expire date = now + defaultexpire
- */
- if (exp == APR_DATE_BAD) {
- if (lastmod != APR_DATE_BAD) {
- apr_time_t x = (apr_time_t) ((date - lastmod) * conf->factor);
- if (x > conf->maxex)
- x = conf->maxex;
- exp = now + x;
- }
- else {
- exp = now + conf->defex;
- }
- }
- info->expire = exp;
-
- info->content_type = apr_pstrdup(r->pool, r->content_type);
- info->filename = apr_pstrdup(r->pool, r->filename );
-
- /*
- * Write away header information to cache.
- */
- rv = cache_write_entity_headers(cache->handle, r, info);
- if (rv == APR_SUCCESS) {
- rv = cache_write_entity_body(cache->handle, r, in);
- }
- if (rv != APR_SUCCESS) {
- ap_remove_output_filter(f);
- }
- return ap_pass_brigade(f->next, in);
-}
-
-/* -------------------------------------------------------------- */
-/* Setup configurable data */
-
-static void * create_cache_config(apr_pool_t *p, server_rec *s)
-{
- cache_server_conf *ps = ap_pcalloc(p, sizeof(cache_server_conf));
-
- /* 1 if the cache is enabled, 0 otherwise */
- ps->cacheon = 0;
- ps->cacheon_set = 0;
- /* array of URL prefixes for which caching is enabled */
- ps->cacheenable = ap_make_array(p, 10, sizeof(struct cache_enable));
- /* array of URL prefixes for which caching is disabled */
- ps->cachedisable = ap_make_array(p, 10, sizeof(struct cache_disable));
- /* maximum time to cache a document */
- ps->maxex = DEFAULT_CACHE_MAXEXPIRE;
- ps->maxex_set = 0;
- /* default time to cache a document */
- ps->defex = DEFAULT_CACHE_EXPIRE;
- ps->defex_set = 0;
- /* factor used to estimate Expires date from LastModified date */
- ps->factor = DEFAULT_CACHE_LMFACTOR;
- ps->factor_set = 0;
- /* default percentage to force cache completion */
- ps->complete = DEFAULT_CACHE_COMPLETION;
- ps->complete_set = 0;
- ps->no_last_mod_ignore_set = 0;
- ps->no_last_mod_ignore = 0;
- ps->ignorecachecontrol = 0;
- ps->ignorecachecontrol_set = 0 ;
- return ps;
-}
-
-static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv)
-{
- cache_server_conf *ps = ap_pcalloc(p, sizeof(cache_server_conf));
- cache_server_conf *base = (cache_server_conf *) basev;
- cache_server_conf *overrides = (cache_server_conf *) overridesv;
-
- /* 1 if the cache is enabled, 0 otherwise */
- ps->cacheon =
- (overrides->cacheon_set == 0) ? base->cacheon : overrides->cacheon;
- /* array of URL prefixes for which caching is disabled */
- ps->cachedisable = ap_append_arrays(p,
- base->cachedisable,
- overrides->cachedisable);
- /* array of URL prefixes for which caching is enabled */
- ps->cacheenable = ap_append_arrays(p,
- base->cacheenable,
- overrides->cacheenable);
- /* maximum time to cache a document */
- ps->maxex = (overrides->maxex_set == 0) ? base->maxex : overrides->maxex;
- /* default time to cache a document */
- ps->defex = (overrides->defex_set == 0) ? base->defex : overrides->defex;
- /* factor used to estimate Expires date from LastModified date */
- ps->factor = (overrides->factor_set == 0) ? base->factor : overrides->factor;
- /* default percentage to force cache completion */
- ps->complete =
- (overrides->complete_set == 0) ? base->complete : overrides->complete;
-
- ps->no_last_mod_ignore =
- (overrides->no_last_mod_ignore_set) ?
- base->no_last_mod_ignore :
- overrides->no_last_mod_ignore;
- ps->ignorecachecontrol =
- (overrides->ignorecachecontrol_set) ?
- base->ignorecachecontrol :
- overrides->ignorecachecontrol;
-
- return ps;
-}
-static const char
-*set_cache_ignore_no_last_mod( cmd_parms *parms, void *dummy, int flag)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
-
- conf->no_last_mod_ignore = 1;
- conf->no_last_mod_ignore_set = 1;
- return NULL;
-
-}
-
-static const char
-*set_cache_on(cmd_parms *parms, void *dummy, int flag)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
-
- conf->cacheon = 1;
- conf->cacheon_set = 1;
- return NULL;
-}
-static const char
-*set_cache_ignore_cachecontrol( cmd_parms *parms, void *dummy, int flag)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
-
- conf->ignorecachecontrol = 1;
- conf->ignorecachecontrol_set = 1;
- return NULL;
-
-}
-
-static const char
-*add_cache_enable(cmd_parms *parms,
- void *dummy,
- const char *type,
- const char *url)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
- struct cache_enable *new;
-
- new = apr_array_push(conf->cacheenable);
- new->type = type;
- new->url = url;
- return NULL;
-}
-
-static const char
-*add_cache_disable(cmd_parms *parms, void *dummy, const char *url)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
- struct cache_enable *new;
-
- new = apr_array_push(conf->cachedisable);
- new->url = url;
- return NULL;
-}
-
-static const char
-*set_cache_maxex(cmd_parms *parms, void *dummy, const char *arg)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
-
- conf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
- conf->maxex_set = 1;
- return NULL;
-}
-
-static const char
-*set_cache_defex(cmd_parms *parms, void *dummy, const char *arg)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
-
- conf->defex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
- conf->defex_set = 1;
- return NULL;
-}
-
-static const char
-*set_cache_factor(cmd_parms *parms, void *dummy, const char *arg)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
- double val;
-
- if (sscanf(arg, "%lg", &val) != 1)
- return "CacheLastModifiedFactor value must be a float";
- conf->factor = val;
- conf->factor_set = 1;
- return NULL;
-}
-
-static const char
-*set_cache_complete(cmd_parms *parms, void *dummy, const char *arg)
-{
- cache_server_conf *conf = ap_get_module_config(parms->server->module_config,
- &cache_module);
- int val;
-
- if (sscanf(arg, "%u", &val) != 1)
- return "CacheForceCompletion value must be a percentage";
- conf->complete = val;
- conf->complete_set = 1;
- return NULL;
-}
-static int
-cache_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
-{
- /* This is the means by which unusual (non-unix) os's may find alternate
- * means to run a given command (e.g. shebang/registry parsing on Win32)
- */
- cache_generate_key = APR_RETRIEVE_OPTIONAL_FN(ap_cache_generate_key);
- if (!cache_generate_key) {
- cache_generate_key = cache_generate_key_default;
- }
- return OK;
-}
-
-static const command_rec cache_cmds[] =
-{
- /* XXX
- * Consider a new config directive that enables loading specific cache
- * implememtations (like mod_cache_mem, mod_cache_file, etc.).
- * Rather than using a LoadModule directive, admin would use something
- * like CacheModule mem_cache_module | file_cache_module, etc,
- * which would cause the approprpriate cache module to be loaded.
- * This is more intuitive that requiring a LoadModule directive.
- */
-
- AP_INIT_FLAG("CacheOn", set_cache_on, NULL, RSRC_CONF,
- "On if the transparent cache should be enabled"),
- AP_INIT_TAKE2("CacheEnable", add_cache_enable, NULL, RSRC_CONF,
- "A cache type and partial URL prefix below which caching is enabled"),
- AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF,
- "A partial URL prefix below which caching is disabled"),
- AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF,
- "The maximum time in seconds to cache a document"),
- AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF,
- "The default time in seconds to cache a document"),
- AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL,
- RSRC_CONF,
- "Ignore Responses where there is no Last Modified Header"),
- AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol, NULL,
- RSRC_CONF,
- "Ignore requests from the client for uncached content"),
- AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF,
- "The factor used to estimate Expires date from LastModified date"),
- AP_INIT_TAKE1("CacheForceCompletion", set_cache_complete, NULL, RSRC_CONF,
- "Percentage of download to arrive for the cache to force complete transfer"),
- {NULL}
-};
-
-static void
-register_hooks(apr_pool_t *p)
-{
- /* cache initializer */
- /* cache handler */
- ap_hook_quick_handler(cache_url_handler, NULL, NULL, APR_HOOK_FIRST);
- /* cache filters
- * XXX The cache filters need to run right after the handlers and before
- * any other filters. Consider creating AP_FTYPE_CACHE for this purpose.
- * Make them AP_FTYPE_CONTENT for now.
- * XXX ianhH:they should run AFTER all the other content filters.
- */
- ap_register_output_filter("CACHE_IN",
- cache_in_filter,
- AP_FTYPE_CONTENT_SET);
- ap_register_output_filter("CACHE_OUT",
- cache_out_filter,
- AP_FTYPE_CONTENT_SET);
- ap_register_output_filter("CACHE_CONDITIONAL",
- cache_conditional_filter,
- AP_FTYPE_CONTENT_SET);
- ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
-}
-
-module AP_MODULE_DECLARE_DATA cache_module =
-{
- STANDARD20_MODULE_STUFF,
- NULL, /* create per-directory config structure */
- NULL, /* merge per-directory config structures */
- create_cache_config, /* create per-server config structure */
- merge_cache_config, /* merge per-server config structures */
- cache_cmds, /* command apr_table_t */
- register_hooks
-};
diff --git a/modules/experimental/mod_cache.dsp b/modules/experimental/mod_cache.dsp
deleted file mode 100644
index c2bec01a47..0000000000
--- a/modules/experimental/mod_cache.dsp
+++ /dev/null
@@ -1,119 +0,0 @@
-# Microsoft Developer Studio Project File - Name="mod_cache" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=mod_cache - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "mod_cache.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "mod_cache.mak" CFG="mod_cache - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_cache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_cache - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "mod_cache - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_CACHE_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../../os/win32" /I "C:\src\db-4.0.14\build_win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CACHE_DECLARE_EXPORT" /D "MOD_CACHE_EXPORTS" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/mod_cache.so"
-
-!ELSEIF "$(CFG)" == "mod_cache - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_CACHE_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../../os/win32" /I "C:\src\db-4.0.14\build_win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CACHE_DECLARE_EXPORT" /D "MOD_CACHE_EXPORTS" /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/mod_cache.so" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "mod_cache - Win32 Release"
-# Name "mod_cache - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\cache_storage.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\cache_util.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\mod_cache.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\mod_cache.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/modules/experimental/mod_cache.h b/modules/experimental/mod_cache.h
deleted file mode 100644
index 2a8106cf3f..0000000000
--- a/modules/experimental/mod_cache.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-#ifndef MOD_CACHE_H
-#define MOD_CACHE_H
-
-/*
- * Main include file for the Apache Transparent Cache
- */
-
-#define CORE_PRIVATE
-
-#include "apr_hooks.h"
-#include "apr.h"
-#include "apr_compat.h"
-#include "apr_lib.h"
-#include "apr_strings.h"
-#include "apr_buckets.h"
-#include "apr_md5.h"
-#include "apr_pools.h"
-#include "apr_strings.h"
-#include "apr_optional.h"
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-
-#include "httpd.h"
-#include "http_config.h"
-#include "ap_config.h"
-#include "http_core.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "http_vhost.h"
-#include "http_main.h"
-#include "http_log.h"
-#include "http_connection.h"
-#include "util_filter.h"
-#include "apr_date.h"
-#include "apr_uri.h"
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-/* default completion is 60% */
-#define DEFAULT_CACHE_COMPLETION (60)
-#define MAX_URL_LENGTH 1024
-#define MSEC_ONE_DAY ((apr_time_t)(86400*APR_USEC_PER_SEC)) /* one day, in microseconds */
-#define MSEC_ONE_HR ((apr_time_t)(3600*APR_USEC_PER_SEC)) /* one hour, in microseconds */
-#define MSEC_ONE_MIN ((apr_time_t)(60*APR_USEC_PER_SEC)) /* one minute, in microseconds */
-#define MSEC_ONE_SEC ((apr_time_t)(APR_USEC_PER_SEC)) /* one second, in microseconds */
-#define DEFAULT_CACHE_MAXEXPIRE MSEC_ONE_DAY
-#define DEFAULT_CACHE_EXPIRE MSEC_ONE_HR
-#define DEFAULT_CACHE_LMFACTOR (0.1)
-
-/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and
- * PROXY_DECLARE_DATA with appropriate export and import tags for the platform
- */
-#if !defined(WIN32)
-#define CACHE_DECLARE(type) type
-#define CACHE_DECLARE_NONSTD(type) type
-#define CACHE_DECLARE_DATA
-#elif defined(CACHE_DECLARE_STATIC)
-#define CACHE_DECLARE(type) type __stdcall
-#define CACHE_DECLARE_NONSTD(type) type
-#define CACHE_DECLARE_DATA
-#elif defined(CACHE_DECLARE_EXPORT)
-#define CACHE_DECLARE(type) __declspec(dllexport) type __stdcall
-#define CACHE_DECLARE_NONSTD(type) __declspec(dllexport) type
-#define CACHE_DECLARE_DATA __declspec(dllexport)
-#else
-#define CACHE_DECLARE(type) __declspec(dllimport) type __stdcall
-#define CACHE_DECLARE_NONSTD(type) __declspec(dllimport) type
-#define CACHE_DECLARE_DATA __declspec(dllimport)
-#endif
-
-struct cache_enable {
- const char *url;
- const char *type;
-};
-
-struct cache_disable {
- const char *url;
-};
-
-/* static information about the local cache */
-typedef struct {
- int cacheon; /* Cache enabled? */
- int cacheon_set;
- apr_array_header_t *cacheenable; /* URLs to cache */
- apr_array_header_t *cachedisable; /* URLs not to cache */
- apr_time_t maxex; /* Maximum time to keep cached files in msecs */
- int maxex_set;
- apr_time_t defex; /* default time to keep cached file in msecs */
- int defex_set;
- double factor; /* factor for estimating expires date */
- int factor_set;
- int complete; /* Force cache completion after this point */
- int complete_set;
- /** ignore the last-modified header when deciding to cache this request */
- int no_last_mod_ignore_set;
- int no_last_mod_ignore;
- /** ignore client's requests for uncached responses */
- int ignorecachecontrol;
- int ignorecachecontrol_set;
-} cache_server_conf;
-
-/* cache info information */
-typedef struct cache_info cache_info;
-struct cache_info {
- char *content_type;
- char *etag;
- char *lastmods; /* last modified of cache entity */
- char *filename;
- apr_time_t date;
- apr_time_t lastmod;
- char lastmod_str[APR_RFC822_DATE_LEN];
- apr_time_t expire;
- apr_time_t request_time;
- apr_time_t response_time;
- apr_size_t len;
-};
-
-/* cache handle information */
-typedef struct cache_object cache_object_t;
-struct cache_object {
- char *key;
- cache_object_t *next;
- cache_info info;
- void *vobj; /* Opaque portion (specific to the cache implementation) of the cache object */
- apr_size_t count; /* Number of body bytes written to the cache so far */
- int complete;
- apr_size_t refcount;
- apr_size_t cleanup;
-};
-
-typedef struct cache_handle cache_handle_t;
-struct cache_handle {
- cache_object_t *cache_obj;
- int (*remove_entity) (cache_handle_t *h);
- apr_status_t (*write_headers)(cache_handle_t *h, request_rec *r, cache_info *i);
- apr_status_t (*write_body)(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);
- apr_status_t (*read_headers) (cache_handle_t *h, request_rec *r);
- apr_status_t (*read_body) (cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
-};
-
-/* per request cache information */
-typedef struct {
- const char *types; /* the types of caches allowed */
- const char *type; /* the type of cache selected */
- int fresh; /* is the entitey fresh? */
- cache_handle_t *handle; /* current cache handle */
- int in_checked; /* CACHE_IN must cache the entity */
-} cache_request_rec;
-
-
-/* cache_util.c */
-/**
- *
- */
-CACHE_DECLARE(apr_time_t) ap_cache_hex2msec(const char *x);
-CACHE_DECLARE(void) ap_cache_msec2hex(apr_time_t j, char *y);
-CACHE_DECLARE(char *) generate_name(apr_pool_t *p, int dirlevels,
- int dirlength,
- const char *name);
-CACHE_DECLARE(int) ap_cache_request_is_conditional(request_rec *r);
-CACHE_DECLARE(void) ap_cache_reset_output_filters(request_rec *r);
-CACHE_DECLARE(const char *)ap_cache_get_cachetype(request_rec *r, cache_server_conf *conf, const char *url);
-CACHE_DECLARE(int) ap_cache_liststr(const char *list, const char *key, char **val);
-CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str);
-
-/**
- * cache_storage.c
- */
-int cache_remove_url(request_rec *r, const char *types, char *url);
-int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t size);
-int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h);
-int cache_select_url(request_rec *r, const char *types, char *url);
-apr_status_t cache_generate_key_default( request_rec *r, apr_pool_t*p, char**key );
-/**
- * create a key for the cache based on the request record
- * this is the 'default' version, which can be overridden by a default function
- */
-const char* cache_create_key( request_rec*r );
-
-apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info);
-apr_status_t cache_write_entity_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *bb);
-
-apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r);
-apr_status_t cache_read_entity_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
-
-
-/* hooks */
-
-/* Create a set of CACHE_DECLARE(type), CACHE_DECLARE_NONSTD(type) and
- * CACHE_DECLARE_DATA with appropriate export and import tags for the platform
- */
-#if !defined(WIN32)
-#define CACHE_DECLARE(type) type
-#define CACHE_DECLARE_NONSTD(type) type
-#define CACHE_DECLARE_DATA
-#elif defined(CACHE_DECLARE_STATIC)
-#define CACHE_DECLARE(type) type __stdcall
-#define CACHE_DECLARE_NONSTD(type) type
-#define CACHE_DECLARE_DATA
-#elif defined(CACHE_DECLARE_EXPORT)
-#define CACHE_DECLARE(type) __declspec(dllexport) type __stdcall
-#define CACHE_DECLARE_NONSTD(type) __declspec(dllexport) type
-#define CACHE_DECLARE_DATA __declspec(dllexport)
-#else
-#define CACHE_DECLARE(type) __declspec(dllimport) type __stdcall
-#define CACHE_DECLARE_NONSTD(type) __declspec(dllimport) type
-#define CACHE_DECLARE_DATA __declspec(dllimport)
-#endif
-
-APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, create_entity,
- (cache_handle_t *h, request_rec *r, const char *type,
- const char *urlkey, apr_size_t len))
-APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, open_entity,
- (cache_handle_t *h, request_rec *r, const char *type,
- const char *urlkey))
-APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_url,
- (const char *type, const char *urlkey))
-
-
-
-APR_DECLARE_OPTIONAL_FN(apr_status_t,
- ap_cache_generate_key,
- (request_rec *r, apr_pool_t*p, char**key ));
-
-
-#endif /*MOD_CACHE_H*/
diff --git a/modules/experimental/mod_case_filter.c b/modules/experimental/mod_case_filter.c
deleted file mode 100644
index c19fa928a9..0000000000
--- a/modules/experimental/mod_case_filter.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Ben messing around... */
-
-#include "httpd.h"
-#include "http_config.h"
-#include "apr_general.h"
-#include "util_filter.h"
-#include "apr_buckets.h"
-#include "http_request.h"
-
-#include <ctype.h>
-
-static const char s_szCaseFilterName[]="CaseFilter";
-module AP_MODULE_DECLARE_DATA case_filter_module;
-
-typedef struct
- {
- int bEnabled;
- } CaseFilterConfig;
-
-static void *CaseFilterCreateServerConfig(apr_pool_t *p,server_rec *s)
- {
- CaseFilterConfig *pConfig=apr_pcalloc(p,sizeof *pConfig);
-
- pConfig->bEnabled=0;
-
- return pConfig;
- }
-
-static void CaseFilterInsertFilter(request_rec *r)
- {
- CaseFilterConfig *pConfig=ap_get_module_config(r->server->module_config,
- &case_filter_module);
-
- if(!pConfig->bEnabled)
- return;
-
- ap_add_output_filter(s_szCaseFilterName,NULL,r,r->connection);
- }
-
-static apr_status_t CaseFilterOutFilter(ap_filter_t *f,
- apr_bucket_brigade *pbbIn)
- {
- apr_bucket *pbktIn;
- apr_bucket_brigade *pbbOut;
-
- /* XXX: is this the most appropriate pool? */
- pbbOut=apr_brigade_create(f->r->pool);
- APR_BRIGADE_FOREACH(pbktIn,pbbIn)
- {
- const char *data;
- apr_size_t len;
- char *buf;
- apr_size_t n;
- apr_bucket *pbktOut;
-
- if(APR_BUCKET_IS_EOS(pbktIn))
- {
- /* XXX: why can't I reuse pbktIn??? */
- apr_bucket *pbktEOS=apr_bucket_eos_create();
- APR_BRIGADE_INSERT_TAIL(pbbOut,pbktEOS);
- continue;
- }
-
- /* read */
- apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ);
-
- /* write */
- buf=malloc(len);
- for(n=0 ; n < len ; ++n)
- buf[n]=toupper(data[n]);
-
- pbktOut=apr_bucket_heap_create(buf,len,0);
- APR_BRIGADE_INSERT_TAIL(pbbOut,pbktOut);
- }
-
- /* XXX: is there any advantage to passing a brigade for each bucket? */
- return ap_pass_brigade(f->next,pbbOut);
- }
-
-static const char *CaseFilterEnable(cmd_parms *cmd, void *dummy, int arg)
- {
- CaseFilterConfig *pConfig=ap_get_module_config(cmd->server->module_config,
- &case_filter_module);
- pConfig->bEnabled=arg;
-
- return NULL;
- }
-
-static const command_rec CaseFilterCmds[] =
- {
- AP_INIT_FLAG("CaseFilter", CaseFilterEnable, NULL, RSRC_CONF,
- "Run a case filter on this host"),
- { NULL }
- };
-
-static void CaseFilterRegisterHooks(apr_pool_t *p)
- {
- ap_hook_insert_filter(CaseFilterInsertFilter,NULL,NULL,APR_HOOK_MIDDLE);
- ap_register_output_filter(s_szCaseFilterName,CaseFilterOutFilter,
- AP_FTYPE_RESOURCE);
- }
-
-module AP_MODULE_DECLARE_DATA case_filter_module =
-{
- STANDARD20_MODULE_STUFF,
- NULL,
- NULL,
- CaseFilterCreateServerConfig,
- NULL,
- CaseFilterCmds,
- CaseFilterRegisterHooks
-};
diff --git a/modules/experimental/mod_case_filter_in.c b/modules/experimental/mod_case_filter_in.c
deleted file mode 100644
index 1bff66d836..0000000000
--- a/modules/experimental/mod_case_filter_in.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- */
-
-/*
- * An example input filter - this converts input to upper case. Note that
- * because of the moment it gets inserted it does NOT convert request headers.
- */
-
-#include "httpd.h"
-#include "http_config.h"
-#include "apr_general.h"
-#include "util_filter.h"
-#include "apr_buckets.h"
-#include "http_request.h"
-
-#include <ctype.h>
-
-static const char s_szCaseFilterName[] = "CaseFilterIn";
-module AP_MODULE_DECLARE_DATA case_filter_in_module;
-
-typedef struct
-{
- int bEnabled;
-} CaseFilterInConfig;
-
-typedef struct
-{
- apr_bucket_brigade *pbbTmp;
-} CaseFilterInContext;
-
-static void *CaseFilterInCreateServerConfig(apr_pool_t *p, server_rec *s)
-{
- CaseFilterInConfig *pConfig = apr_pcalloc(p, sizeof *pConfig);
-
- pConfig->bEnabled = 0;
-
- return pConfig;
-}
-
-static void CaseFilterInInsertFilter(request_rec *r)
-{
- CaseFilterInConfig *pConfig=ap_get_module_config(r->server->module_config,
- &case_filter_in_module);
- if(!pConfig->bEnabled)
- return;
-
- ap_add_input_filter(s_szCaseFilterName,NULL,r,r->connection);
-}
-
-static apr_status_t CaseFilterInFilter(ap_filter_t *f,
- apr_bucket_brigade *pbbOut,
- ap_input_mode_t eMode,
- apr_read_type_e eBlock,
- apr_off_t nBytes)
-{
- request_rec *r = f->r;
- CaseFilterInContext *pCtx;
- apr_status_t ret;
-
- if (!(pCtx = f->ctx)) {
- f->ctx = pCtx = apr_palloc(r->pool, sizeof *pCtx);
- pCtx->pbbTmp = apr_brigade_create(r->pool);
- }
-
- if (APR_BRIGADE_EMPTY(pCtx->pbbTmp)) {
- ret = ap_get_brigade(f->next, pCtx->pbbTmp, eMode, eBlock, nBytes);
-
- if (eMode == AP_MODE_EATCRLF || ret != APR_SUCCESS)
- return ret;
- }
-
- while(!APR_BRIGADE_EMPTY(pCtx->pbbTmp)) {
- apr_bucket *pbktIn = APR_BRIGADE_FIRST(pCtx->pbbTmp);
- apr_bucket *pbktOut;
- const char *data;
- apr_size_t len;
- char *buf;
- int n;
-
- /* It is tempting to do this...
- * APR_BUCKET_REMOVE(pB);
- * APR_BRIGADE_INSERT_TAIL(pbbOut,pB);
- * and change the case of the bucket data, but that would be wrong
- * for a file or socket buffer, for example...
- */
-
- if(APR_BUCKET_IS_EOS(pbktIn)) {
- APR_BUCKET_REMOVE(pbktIn);
- APR_BRIGADE_INSERT_TAIL(pbbOut, pbktIn);
- break;
- }
-
- ret=apr_bucket_read(pbktIn, &data, &len, eBlock);
- if(ret != APR_SUCCESS)
- return ret;
-
- buf = malloc(len);
- for(n=0 ; n < len ; ++n)
- buf[n] = toupper(data[n]);
-
- pbktOut = apr_bucket_heap_create(buf, len, 0);
- APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut);
- apr_bucket_delete(pbktIn);
- }
-
- return APR_SUCCESS;
-}
-
-
-static const char *CaseFilterInEnable(cmd_parms *cmd, void *dummy, int arg)
-{
- CaseFilterInConfig *pConfig
- = ap_get_module_config(cmd->server->module_config,
- &case_filter_in_module);
- pConfig->bEnabled=arg;
-
- return NULL;
-}
-
-static const command_rec CaseFilterInCmds[] =
-{
- AP_INIT_FLAG("CaseFilterIn", CaseFilterInEnable, NULL, RSRC_CONF,
- "Run an input case filter on this host"),
- { NULL }
-};
-
-
-static void CaseFilterInRegisterHooks(apr_pool_t *p)
-{
- ap_hook_insert_filter(CaseFilterInInsertFilter, NULL, NULL,
- APR_HOOK_MIDDLE);
- ap_register_input_filter(s_szCaseFilterName, CaseFilterInFilter,
- AP_FTYPE_RESOURCE);
-}
-
-module AP_MODULE_DECLARE_DATA case_filter_in_module =
-{
- STANDARD20_MODULE_STUFF,
- NULL,
- NULL,
- CaseFilterInCreateServerConfig,
- NULL,
- CaseFilterInCmds,
- CaseFilterInRegisterHooks
-};
diff --git a/modules/experimental/mod_charset_lite.c b/modules/experimental/mod_charset_lite.c
deleted file mode 100644
index 7b99ddc331..0000000000
--- a/modules/experimental/mod_charset_lite.c
+++ /dev/null
@@ -1,1118 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-/*
- * simple hokey charset recoding configuration module
- *
- * See mod_ebcdic and mod_charset for more thought-out examples. This
- * one is just so Jeff can learn how a module works and experiment with
- * basic character set recoding configuration.
- *
- * !!!This is an extremely cheap ripoff of mod_charset.c from Russian Apache!!!
- */
-
-#include "httpd.h"
-#include "http_config.h"
-#define CORE_PRIVATE
-#include "http_core.h"
-#include "http_log.h"
-#include "http_main.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "util_charset.h"
-#include "apr_buckets.h"
-#include "util_filter.h"
-#include "apr_strings.h"
-#include "apr_lib.h"
-#include "apr_xlate.h"
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-
-#define OUTPUT_XLATE_BUF_SIZE (16*1024) /* size of translation buffer used on output */
-#define INPUT_XLATE_BUF_SIZE (8*1024) /* size of translation buffer used on input */
-
-#define XLATE_MIN_BUFF_LEFT 128 /* flush once there is no more than this much
- * space left in the translation buffer
- */
-
-#define FATTEST_CHAR 8 /* we don't handle chars wider than this that straddle
- * two buckets
- */
-
-/* extended error status codes; this is used in addition to an apr_status_t to
- * track errors in the translation filter
- */
-typedef enum {
- EES_INIT = 0, /* no error info yet; value must be 0 for easy init */
- EES_LIMIT, /* built-in restriction encountered */
- EES_INCOMPLETE_CHAR, /* incomplete multi-byte char at end of content */
- EES_BUCKET_READ,
- EES_DOWNSTREAM, /* something bad happened in a filter below xlate */
- EES_BAD_INPUT /* input data invalid */
-} ees_t;
-
-/* registered name of the output translation filter */
-#define XLATEOUT_FILTER_NAME "XLATEOUT"
-/* registered name of input translation filter */
-#define XLATEIN_FILTER_NAME "XLATEIN"
-
-typedef struct charset_dir_t {
- /** debug level; -1 means uninitialized, 0 means no debug */
- int debug;
- const char *charset_source; /* source encoding */
- const char *charset_default; /* how to ship on wire */
- /** module does ap_add_*_filter()? */
- enum {IA_INIT, IA_IMPADD, IA_NOIMPADD} implicit_add;
-} charset_dir_t;
-
-/* charset_filter_ctx_t is created for each filter instance; because the same
- * filter code is used for translating in both directions, we need this context
- * data to tell the filter which translation handle to use; it also can hold a
- * character which was split between buckets
- */
-typedef struct charset_filter_ctx_t {
- apr_xlate_t *xlate;
- charset_dir_t *dc;
- ees_t ees; /* extended error status */
- apr_size_t saved;
- char buf[FATTEST_CHAR]; /* we want to be able to build a complete char here */
- int ran; /* has filter instance run before? */
- int noop; /* should we pass brigades through unchanged? */
- char *tmp; /* buffer for input filtering */
- apr_bucket_brigade *bb; /* input buckets we couldn't finish translating */
-} charset_filter_ctx_t;
-
-/* charset_req_t is available via r->request_config if any translation is
- * being performed
- */
-typedef struct charset_req_t {
- charset_dir_t *dc;
- charset_filter_ctx_t *output_ctx, *input_ctx;
-} charset_req_t;
-
-/* debug level definitions */
-#define DBGLVL_GORY 9 /* gory details */
-#define DBGLVL_FLOW 4 /* enough messages to see what happens on
- * each request */
-#define DBGLVL_PMC 2 /* messages about possible misconfiguration */
-
-module AP_MODULE_DECLARE_DATA charset_lite_module;
-
-static void *create_charset_dir_conf(apr_pool_t *p,char *dummy)
-{
- charset_dir_t *dc = (charset_dir_t *)apr_pcalloc(p,sizeof(charset_dir_t));
-
- dc->debug = -1;
- return dc;
-}
-
-static void *merge_charset_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
-{
- charset_dir_t *a = (charset_dir_t *)apr_pcalloc (p, sizeof(charset_dir_t));
- charset_dir_t *base = (charset_dir_t *)basev,
- *over = (charset_dir_t *)overridesv;
-
- /* If it is defined in the current container, use it. Otherwise, use the one
- * from the enclosing container.
- */
-
- a->debug =
- over->debug != -1 ? over->debug : base->debug;
- a->charset_default =
- over->charset_default ? over->charset_default : base->charset_default;
- a->charset_source =
- over->charset_source ? over->charset_source : base->charset_source;
- a->implicit_add =
- over->implicit_add != IA_INIT ? over->implicit_add : base->implicit_add;
- return a;
-}
-
-/* CharsetSourceEnc charset
- */
-static const char *add_charset_source(cmd_parms *cmd, void *in_dc,
- const char *name)
-{
- charset_dir_t *dc = in_dc;
-
- dc->charset_source = name;
- return NULL;
-}
-
-/* CharsetDefault charset
- */
-static const char *add_charset_default(cmd_parms *cmd, void *in_dc,
- const char *name)
-{
- charset_dir_t *dc = in_dc;
-
- dc->charset_default = name;
- return NULL;
-}
-
-/* CharsetOptions optionflag...
- */
-static const char *add_charset_options(cmd_parms *cmd, void *in_dc,
- const char *flag)
-{
- charset_dir_t *dc = in_dc;
-
- if (!strcasecmp(flag, "ImplicitAdd")) {
- dc->implicit_add = IA_IMPADD;
- }
- else if (!strcasecmp(flag, "NoImplicitAdd")) {
- dc->implicit_add = IA_NOIMPADD;
- }
- else if (!strncasecmp(flag, "DebugLevel=", 11)) {
- dc->debug = atoi(flag + 11);
- }
- else {
- return apr_pstrcat(cmd->temp_pool,
- "Invalid CharsetOptions option: ",
- flag,
- NULL);
- }
-
- return NULL;
-}
-
-/* find_code_page() is a fixup hook that decides if translation should be
- * enabled; if so, it sets up request data for use by the filter registration
- * hook so that it knows what to do
- */
-static int find_code_page(request_rec *r)
-{
- charset_dir_t *dc = ap_get_module_config(r->per_dir_config,
- &charset_lite_module);
- charset_req_t *reqinfo;
- charset_filter_ctx_t *input_ctx, *output_ctx;
- apr_status_t rv;
- const char *mime_type;
-
- if (dc->debug >= DBGLVL_FLOW) {
- ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "uri: %s file: %s method: %d "
- "imt: %s flags: %s%s%s %s->%s",
- r->uri, r->filename, r->method_number,
- r->content_type ? r->content_type : "(unknown)",
- r->main ? "S" : "", /* S if subrequest */
- r->prev ? "R" : "", /* R if redirect */
- r->proxyreq ? "P" : "", /* P if proxy */
- dc->charset_source, dc->charset_default);
- }
-
- /* If we don't have a full directory configuration, bail out.
- */
- if (!dc->charset_source || !dc->charset_default) {
- if (dc->debug >= DBGLVL_PMC) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "incomplete configuration: src %s, dst %s",
- dc->charset_source ? dc->charset_source : "unspecified",
- dc->charset_default ? dc->charset_default : "unspecified");
- }
- return DECLINED;
- }
-
- /* catch proxy requests */
- if (r->proxyreq) return DECLINED;
- /* mod_rewrite indicators */
- if (!strncmp(r->filename, "redirect:", 9)) return DECLINED;
- if (!strncmp(r->filename, "gone:", 5)) return DECLINED;
- if (!strncmp(r->filename, "passthrough:", 12)) return DECLINED;
- if (!strncmp(r->filename, "forbidden:", 10)) return DECLINED;
-
- mime_type = r->content_type ? r->content_type : ap_default_type(r);
-
- /* If mime type isn't text or message, bail out.
- */
-
-/* XXX When we handle translation of the request body, watch out here as
- * 1.3 allowed additional mime types: multipart and
- * application/x-www-form-urlencoded
- */
-
- if (strncasecmp(mime_type, "text/", 5) &&
-#if APR_CHARSET_EBCDIC
- /* On an EBCDIC machine, be willing to translate mod_autoindex-
- * generated output. Otherwise, it doesn't look too cool.
- *
- * XXX This isn't a perfect fix because this doesn't trigger us
- * to convert from the charset of the source code to ASCII. The
- * general solution seems to be to allow a generator to set an
- * indicator in the r specifying that the body is coded in the
- * implementation character set (i.e., the charset of the source
- * code). This would get several different types of documents
- * translated properly: mod_autoindex output, mod_status output,
- * mod_info output, hard-coded error documents, etc.
- */
- strcmp(mime_type, DIR_MAGIC_TYPE) &&
-#endif
- strncasecmp(mime_type, "message/", 8)) {
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "mime type is %s; no translation selected",
- mime_type);
- }
- return DECLINED;
- }
-
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "charset_source: %s charset_default: %s",
- dc && dc->charset_source ? dc->charset_source : "(none)",
- dc && dc->charset_default ? dc->charset_default : "(none)");
- }
-
- /* Get storage for the request data and the output filter context.
- * We rarely need the input filter context, so allocate that separately.
- */
- reqinfo = (charset_req_t *)apr_pcalloc(r->pool,
- sizeof(charset_req_t) +
- sizeof(charset_filter_ctx_t));
- output_ctx = (charset_filter_ctx_t *)(reqinfo + 1);
-
- reqinfo->dc = dc;
- output_ctx->dc = dc;
- ap_set_module_config(r->request_config, &charset_lite_module, reqinfo);
-
- reqinfo->output_ctx = output_ctx;
- rv = apr_xlate_open(&output_ctx->xlate,
- dc->charset_default, dc->charset_source, r->pool);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "can't open translation %s->%s",
- dc->charset_source, dc->charset_default);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- switch (r->method_number) {
- case M_PUT:
- case M_POST:
- /* Set up input translation. Note: A request body can be included
- * with the OPTIONS method, but for now we don't set up translation
- * of it.
- */
- input_ctx = apr_pcalloc(r->pool, sizeof(charset_filter_ctx_t));
- input_ctx->bb = apr_brigade_create(r->pool);
- input_ctx->tmp = apr_palloc(r->pool, INPUT_XLATE_BUF_SIZE);
- input_ctx->dc = dc;
- reqinfo->input_ctx = input_ctx;
- rv = apr_xlate_open(&input_ctx->xlate, dc->charset_source,
- dc->charset_default, r->pool);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "can't open translation %s->%s",
- dc->charset_default, dc->charset_source);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- }
-
- return DECLINED;
-}
-
-static int configured_in_list(request_rec *r, const char *filter_name,
- struct ap_filter_t *filter_list)
-{
- struct ap_filter_t *filter = filter_list;
-
- while (filter) {
- if (!strcasecmp(filter_name, filter->frec->name)) {
- return 1;
- }
- filter = filter->next;
- }
- return 0;
-}
-
-static int configured_on_input(request_rec *r, const char *filter_name)
-{
- return configured_in_list(r, filter_name, r->input_filters);
-}
-
-static int configured_on_output(request_rec *r, const char *filter_name)
-{
- return configured_in_list(r, filter_name, r->output_filters);
-}
-
-/* xlate_insert_filter() is a filter hook which decides whether or not
- * to insert a translation filter for the current request.
- */
-static void xlate_insert_filter(request_rec *r)
-{
- /* Hey... don't be so quick to use reqinfo->dc here; reqinfo may be NULL */
- charset_req_t *reqinfo = ap_get_module_config(r->request_config,
- &charset_lite_module);
- charset_dir_t *dc = ap_get_module_config(r->per_dir_config,
- &charset_lite_module);
-
- if (reqinfo) {
- if (reqinfo->output_ctx && !configured_on_output(r, XLATEOUT_FILTER_NAME)) {
- ap_add_output_filter(XLATEOUT_FILTER_NAME, reqinfo->output_ctx, r,
- r->connection);
- }
- else if (dc->debug >= DBGLVL_FLOW) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "xlate output filter not added implicitly because %s",
- !reqinfo->output_ctx ?
- "no output configuration available" :
- "another module added the filter");
- }
-
- if (reqinfo->input_ctx && !configured_on_input(r, XLATEIN_FILTER_NAME)) {
- ap_add_input_filter(XLATEIN_FILTER_NAME, reqinfo->input_ctx, r,
- r->connection);
- }
- else if (dc->debug >= DBGLVL_FLOW) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
- "xlate input filter not added implicitly because %s",
- !reqinfo->input_ctx ?
- "no input configuration available" :
- "another module added the filter");
- }
- }
-}
-
-/* stuff that sucks that I know of:
- *
- * bucket handling:
- * why create an eos bucket when we see it come down the stream? just send the one
- * passed as input... news flash: this will be fixed when xlate_out_filter() starts
- * using the more generic xlate_brigade()
- *
- * translation mechanics:
- * we don't handle characters that straddle more than two buckets; an error
- * will be generated
- */
-
-/* send_downstream() is passed the translated data; it puts it in a single-
- * bucket brigade and passes the brigade to the next filter
- */
-static apr_status_t send_downstream(ap_filter_t *f, const char *tmp, apr_size_t len)
-{
- apr_bucket_brigade *bb;
- apr_bucket *b;
- charset_filter_ctx_t *ctx = f->ctx;
- apr_status_t rv;
-
- bb = apr_brigade_create(f->r->pool);
- b = apr_bucket_transient_create(tmp, len);
- APR_BRIGADE_INSERT_TAIL(bb, b);
- rv = ap_pass_brigade(f->next, bb);
- if (rv != APR_SUCCESS) {
- ctx->ees = EES_DOWNSTREAM;
- }
- return rv;
-}
-
-static apr_status_t send_eos(ap_filter_t *f)
-{
- apr_bucket_brigade *bb;
- apr_bucket *b;
- charset_filter_ctx_t *ctx = f->ctx;
- apr_status_t rv;
-
- bb = apr_brigade_create(f->r->pool);
- b = apr_bucket_eos_create();
- APR_BRIGADE_INSERT_TAIL(bb, b);
- rv = ap_pass_brigade(f->next, bb);
- if (rv != APR_SUCCESS) {
- ctx->ees = EES_DOWNSTREAM;
- }
- return rv;
-}
-
-static apr_status_t set_aside_partial_char(charset_filter_ctx_t *ctx,
- const char *partial,
- apr_size_t partial_len)
-{
- apr_status_t rv;
-
- if (sizeof(ctx->buf) > partial_len) {
- ctx->saved = partial_len;
- memcpy(ctx->buf, partial, partial_len);
- rv = APR_SUCCESS;
- }
- else {
- rv = APR_INCOMPLETE;
- ctx->ees = EES_LIMIT; /* we don't handle chars this wide which straddle
- * buckets
- */
- }
- return rv;
-}
-
-static apr_status_t finish_partial_char(charset_filter_ctx_t *ctx,
- /* input buffer: */
- const char **cur_str,
- apr_size_t *cur_len,
- /* output buffer: */
- char **out_str,
- apr_size_t *out_len)
-{
- apr_status_t rv;
- apr_size_t tmp_input_len;
-
- /* Keep adding bytes from the input string to the saved string until we
- * 1) finish the input char
- * 2) get an error
- * or 3) run out of bytes to add
- */
-
- do {
- ctx->buf[ctx->saved] = **cur_str;
- ++ctx->saved;
- ++*cur_str;
- --*cur_len;
- tmp_input_len = ctx->saved;
- rv = apr_xlate_conv_buffer(ctx->xlate,
- ctx->buf,
- &tmp_input_len,
- *out_str,
- out_len);
- } while (rv == APR_INCOMPLETE && *cur_len);
-
- if (rv == APR_SUCCESS) {
- ctx->saved = 0;
- }
- else {
- ctx->ees = EES_LIMIT; /* code isn't smart enough to handle chars
- * straddling more than two buckets
- */
- }
-
- return rv;
-}
-
-static void log_xlate_error(ap_filter_t *f, apr_status_t rv)
-{
- charset_filter_ctx_t *ctx = f->ctx;
- const char *msg;
- char msgbuf[100];
- int cur;
- int flags = APLOG_ERR;
-
- switch(ctx->ees) {
- case EES_LIMIT:
- flags |= APLOG_NOERRNO;
- msg = "xlate filter - a built-in restriction was encountered";
- break;
- case EES_BAD_INPUT:
- flags |= APLOG_NOERRNO;
- msg = "xlate filter - an input character was invalid";
- break;
- case EES_BUCKET_READ:
- msg = "xlate filter - bucket read routine failed";
- break;
- case EES_INCOMPLETE_CHAR:
- flags |= APLOG_NOERRNO;
- strcpy(msgbuf, "xlate filter - incomplete char at end of input - ");
- cur = 0;
- while (cur < ctx->saved) {
- apr_snprintf(msgbuf + strlen(msgbuf), sizeof(msgbuf) - strlen(msgbuf),
- "%02X", (unsigned)ctx->buf[cur]);
- ++cur;
- }
- msg = msgbuf;
- break;
- case EES_DOWNSTREAM:
- msg = "xlate filter - an error occurred in a lower filter";
- break;
- default:
- msg = "xlate filter - returning error";
- }
- ap_log_rerror(APLOG_MARK, flags, rv, f->r,
- "%s", msg);
-}
-
-/* chk_filter_chain() is called once per filter instance; it tries to
- * determine if the current filter instance should be disabled because
- * its translation is incompatible with the translation of an existing
- * instance of the translate filter
- *
- * Example bad scenario:
- *
- * configured filter chain for the request:
- * INCLUDES XLATEOUT(8859-1->UTS-16)
- * configured filter chain for the subrequest:
- * XLATEOUT(8859-1->UTS-16)
- *
- * When the subrequest is processed, the filter chain will be
- * XLATEOUT(8859-1->UTS-16) XLATEOUT(8859-1->UTS-16)
- * This makes no sense, so the instance of XLATEOUT added for the
- * subrequest will be noop-ed.
- *
- * Example good scenario:
- *
- * configured filter chain for the request:
- * INCLUDES XLATEOUT(8859-1->UTS-16)
- * configured filter chain for the subrequest:
- * XLATEOUT(IBM-1047->8859-1)
- *
- * When the subrequest is processed, the filter chain will be
- * XLATEOUT(IBM-1047->8859-1) XLATEOUT(8859-1->UTS-16)
- * This makes sense, so the instance of XLATEOUT added for the
- * subrequest will be left alone and it will translate from
- * IBM-1047->8859-1.
- */
-static void chk_filter_chain(ap_filter_t *f)
-{
- ap_filter_t *curf;
- charset_filter_ctx_t *curctx, *last_xlate_ctx = NULL,
- *ctx = f->ctx;
- int debug = ctx->dc->debug;
- int output = !strcasecmp(f->frec->name, XLATEOUT_FILTER_NAME);
-
- if (ctx->noop) {
- return;
- }
-
- /* walk the filter chain; see if it makes sense for our filter to
- * do any translation
- */
- curf = output ? f->r->output_filters : f->r->input_filters;
- while (curf) {
- if (!strcasecmp(curf->frec->name, f->frec->name) &&
- curf->ctx) {
- curctx = (charset_filter_ctx_t *)curf->ctx;
- if (!last_xlate_ctx) {
- last_xlate_ctx = curctx;
- }
- else {
- if (strcmp(last_xlate_ctx->dc->charset_default,
- curctx->dc->charset_source)) {
- /* incompatible translation
- * if our filter instance is incompatible with an instance
- * already in place, noop our instance
- * Notes:
- * . We are only willing to noop our own instance.
- * . It is possible to noop another instance which has not
- * yet run, but this is not currently implemented.
- * Hopefully it will not be needed.
- * . It is not possible to noop an instance which has
- * already run.
- */
- if (last_xlate_ctx == f->ctx) {
- last_xlate_ctx->noop = 1;
- if (debug >= DBGLVL_PMC) {
- const char *symbol = output ? "->" : "<-";
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO,
- 0, f->r,
- "%s %s - disabling "
- "translation %s%s%s; existing "
- "translation %s%s%s",
- f->r->uri ? "uri" : "file",
- f->r->uri ? f->r->uri : f->r->filename,
- last_xlate_ctx->dc->charset_source,
- symbol,
- last_xlate_ctx->dc->charset_default,
- curctx->dc->charset_source,
- symbol,
- curctx->dc->charset_default);
- }
- }
- else {
- const char *symbol = output ? "->" : "<-";
-
- ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO,
- 0, f->r,
- "chk_filter_chain() - can't disable "
- "translation %s%s%s; existing "
- "translation %s%s%s",
- last_xlate_ctx->dc->charset_source,
- symbol,
- last_xlate_ctx->dc->charset_default,
- curctx->dc->charset_source,
- symbol,
- curctx->dc->charset_default);
- }
- break;
- }
- }
- }
- curf = curf->next;
- }
-}
-
-/* xlate_brigade() is used to filter request and response bodies
- *
- * we'll stop when one of the following occurs:
- * . we run out of buckets
- * . we run out of space in the output buffer
- * . we hit an error
- *
- * inputs:
- * bb: brigade to process
- * buffer: storage to hold the translated characters
- * buffer_size: size of buffer
- * (and a few more uninteresting parms)
- *
- * outputs:
- * return value: APR_SUCCESS or some error code
- * bb: we've removed any buckets representing the
- * translated characters; the eos bucket, if
- * present, will be left in the brigade
- * buffer: filled in with translated characters
- * buffer_size: updated with the bytes remaining
- * hit_eos: did we hit an EOS bucket?
- */
-static apr_status_t xlate_brigade(charset_filter_ctx_t *ctx,
- apr_bucket_brigade *bb,
- char *buffer,
- apr_size_t *buffer_avail,
- int *hit_eos)
-{
- apr_bucket *b = NULL; /* set to NULL only to quiet some gcc */
- apr_bucket *consumed_bucket;
- const char *bucket;
- apr_size_t bytes_in_bucket; /* total bytes read from current bucket */
- apr_size_t bucket_avail; /* bytes left in current bucket */
- apr_status_t rv = APR_SUCCESS;
-
- *hit_eos = 0;
- bucket_avail = 0;
- consumed_bucket = NULL;
- while (1) {
- if (!bucket_avail) { /* no bytes left to process in the current bucket... */
- if (consumed_bucket) {
- apr_bucket_delete(consumed_bucket);
- consumed_bucket = NULL;
- }
- b = APR_BRIGADE_FIRST(bb);
- if (b == APR_BRIGADE_SENTINEL(bb) ||
- APR_BUCKET_IS_EOS(b)) {
- break;
- }
- rv = apr_bucket_read(b, &bucket, &bytes_in_bucket, APR_BLOCK_READ);
- if (rv != APR_SUCCESS) {
- ctx->ees = EES_BUCKET_READ;
- break;
- }
- bucket_avail = bytes_in_bucket;
- consumed_bucket = b; /* for axing when we're done reading it */
- }
- if (bucket_avail) {
- /* We've got data, so translate it. */
- if (ctx->saved) {
- /* Rats... we need to finish a partial character from the previous
- * bucket.
- *
- * Strangely, finish_partial_char() increments the input buffer
- * pointer but does not increment the output buffer pointer.
- */
- apr_size_t old_buffer_avail = *buffer_avail;
- rv = finish_partial_char(ctx,
- &bucket, &bucket_avail,
- &buffer, buffer_avail);
- buffer += old_buffer_avail - *buffer_avail;
- }
- else {
- apr_size_t old_buffer_avail = *buffer_avail;
- apr_size_t old_bucket_avail = bucket_avail;
- rv = apr_xlate_conv_buffer(ctx->xlate,
- bucket, &bucket_avail,
- buffer,
- buffer_avail);
- buffer += old_buffer_avail - *buffer_avail;
- bucket += old_bucket_avail - bucket_avail;
-
- if (rv == APR_INCOMPLETE) { /* partial character at end of input */
- /* We need to save the final byte(s) for next time; we can't
- * convert it until we look at the next bucket.
- */
- rv = set_aside_partial_char(ctx, bucket, bucket_avail);
- bucket_avail = 0;
- }
- }
- if (rv != APR_SUCCESS) {
- /* bad input byte or partial char too big to store */
- break;
- }
- if (*buffer_avail < XLATE_MIN_BUFF_LEFT) {
- /* if any data remains in the current bucket, split there */
- if (bucket_avail) {
- apr_bucket_split(b, bytes_in_bucket - bucket_avail);
- }
- apr_bucket_delete(b);
- break;
- }
- }
- }
-
- if (!APR_BRIGADE_EMPTY(bb)) {
- b = APR_BRIGADE_FIRST(bb);
- if (APR_BUCKET_IS_EOS(b)) {
- /* Leave the eos bucket in the brigade for reporting to
- * subsequent filters.
- */
- *hit_eos = 1;
- if (ctx->saved) {
- /* Oops... we have a partial char from the previous bucket
- * that won't be completed because there's no more data.
- */
- rv = APR_INCOMPLETE;
- ctx->ees = EES_INCOMPLETE_CHAR;
- }
- }
- }
-
- return rv;
-}
-
-/* xlate_out_filter() handles (almost) arbitrary conversions from one charset
- * to another...
- * translation is determined in the fixup hook (find_code_page), which is
- * where the filter's context data is set up... the context data gives us
- * the translation handle
- */
-static apr_status_t xlate_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- charset_req_t *reqinfo = ap_get_module_config(f->r->request_config,
- &charset_lite_module);
- charset_dir_t *dc = ap_get_module_config(f->r->per_dir_config,
- &charset_lite_module);
- charset_filter_ctx_t *ctx = f->ctx;
- apr_bucket *dptr, *consumed_bucket;
- const char *cur_str;
- apr_size_t cur_len, cur_avail;
- char tmp[OUTPUT_XLATE_BUF_SIZE];
- apr_size_t space_avail;
- int done;
- apr_status_t rv = APR_SUCCESS;
-
- if (!ctx) {
- /* this is SetOutputFilter path; grab the preallocated context,
- * if any; note that if we decided not to do anything in an earlier
- * handler, we won't even have a reqinfo
- */
- if (reqinfo) {
- ctx = f->ctx = reqinfo->output_ctx;
- reqinfo->output_ctx = NULL; /* prevent SNAFU if user coded us twice
- * in the filter chain; we can't have two
- * instances using the same context
- */
- }
- if (!ctx) { /* no idea how to translate; don't do anything */
- ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(charset_filter_ctx_t));
- ctx->dc = dc;
- ctx->noop = 1;
- }
- }
-
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r,
- "xlate_out_filter() - "
- "charset_source: %s charset_default: %s",
- dc && dc->charset_source ? dc->charset_source : "(none)",
- dc && dc->charset_default ? dc->charset_default : "(none)");
- }
-
- if (!ctx->ran) { /* filter never ran before */
- chk_filter_chain(f);
- ctx->ran = 1;
- }
-
- if (ctx->noop) {
- return ap_pass_brigade(f->next, bb);
- }
-
- dptr = APR_BRIGADE_FIRST(bb);
- done = 0;
- cur_len = 0;
- space_avail = sizeof(tmp);
- consumed_bucket = NULL;
- while (!done) {
- if (!cur_len) { /* no bytes left to process in the current bucket... */
- if (consumed_bucket) {
- apr_bucket_delete(consumed_bucket);
- consumed_bucket = NULL;
- }
- if (dptr == APR_BRIGADE_SENTINEL(bb)) {
- done = 1;
- break;
- }
- if (APR_BUCKET_IS_EOS(dptr)) {
- done = 1;
- cur_len = -1; /* XXX yuck, but that tells us to send
- * eos down; when we minimize our bb construction
- * we'll fix this crap */
- if (ctx->saved) {
- /* Oops... we have a partial char from the previous bucket
- * that won't be completed because there's no more data.
- */
- rv = APR_INCOMPLETE;
- ctx->ees = EES_INCOMPLETE_CHAR;
- }
- break;
- }
- rv = apr_bucket_read(dptr, &cur_str, &cur_len, APR_BLOCK_READ);
- if (rv != APR_SUCCESS) {
- done = 1;
- ctx->ees = EES_BUCKET_READ;
- break;
- }
- consumed_bucket = dptr; /* for axing when we're done reading it */
- dptr = APR_BUCKET_NEXT(dptr); /* get ready for when we access the
- * next bucket */
- }
- /* Try to fill up our tmp buffer with translated data. */
- cur_avail = cur_len;
-
- if (cur_len) { /* maybe we just hit the end of a pipe (len = 0) ? */
- if (ctx->saved) {
- /* Rats... we need to finish a partial character from the previous
- * bucket.
- */
- char *tmp_tmp;
-
- tmp_tmp = tmp + sizeof(tmp) - space_avail;
- rv = finish_partial_char(ctx,
- &cur_str, &cur_len,
- &tmp_tmp, &space_avail);
- }
- else {
- rv = apr_xlate_conv_buffer(ctx->xlate,
- cur_str, &cur_avail,
- tmp + sizeof(tmp) - space_avail, &space_avail);
-
- /* Update input ptr and len after consuming some bytes */
- cur_str += cur_len - cur_avail;
- cur_len = cur_avail;
-
- if (rv == APR_INCOMPLETE) { /* partial character at end of input */
- /* We need to save the final byte(s) for next time; we can't
- * convert it until we look at the next bucket.
- */
- rv = set_aside_partial_char(ctx, cur_str, cur_len);
- cur_len = 0;
- }
- }
- }
-
- if (rv != APR_SUCCESS) {
- /* bad input byte or partial char too big to store */
- done = 1;
- }
-
- if (space_avail < XLATE_MIN_BUFF_LEFT) {
- /* It is time to flush, as there is not enough space left in the
- * current output buffer to bother with converting more data.
- */
- rv = send_downstream(f, tmp, sizeof(tmp) - space_avail);
- if (rv != APR_SUCCESS) {
- done = 1;
- }
-
- /* tmp is now empty */
- space_avail = sizeof(tmp);
- }
- }
-
- if (rv == APR_SUCCESS) {
- if (space_avail < sizeof(tmp)) { /* gotta write out what we converted */
- rv = send_downstream(f, tmp, sizeof(tmp) - space_avail);
- }
- }
- if (rv == APR_SUCCESS) {
- if (cur_len == -1) {
- rv = send_eos(f);
- }
- }
- else {
- log_xlate_error(f, rv);
- }
-
- return rv;
-}
-
-static int xlate_in_filter(ap_filter_t *f, apr_bucket_brigade *bb,
- ap_input_mode_t mode, apr_read_type_e block,
- apr_off_t readbytes)
-{
- apr_status_t rv;
- charset_req_t *reqinfo = ap_get_module_config(f->r->request_config,
- &charset_lite_module);
- charset_dir_t *dc = ap_get_module_config(f->r->per_dir_config,
- &charset_lite_module);
- charset_filter_ctx_t *ctx = f->ctx;
- apr_size_t buffer_size;
- int hit_eos;
-
- if (!ctx) {
- /* this is SetInputFilter path; grab the preallocated context,
- * if any; note that if we decided not to do anything in an earlier
- * handler, we won't even have a reqinfo
- */
- if (reqinfo) {
- ctx = f->ctx = reqinfo->input_ctx;
- reqinfo->input_ctx = NULL; /* prevent SNAFU if user coded us twice
- * in the filter chain; we can't have two
- * instances using the same context
- */
- }
- if (!ctx) { /* no idea how to translate; don't do anything */
- ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(charset_filter_ctx_t));
- ctx->dc = dc;
- ctx->noop = 1;
- }
- }
-
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r,
- "xlate_in_filter() - "
- "charset_source: %s charset_default: %s",
- dc && dc->charset_source ? dc->charset_source : "(none)",
- dc && dc->charset_default ? dc->charset_default : "(none)");
- }
-
- if (!ctx->ran) { /* filter never ran before */
- chk_filter_chain(f);
- ctx->ran = 1;
- }
-
- if (ctx->noop) {
- return ap_get_brigade(f->next, bb, mode, block, readbytes);
- }
-
- if (APR_BRIGADE_EMPTY(ctx->bb)) {
- if ((rv = ap_get_brigade(f->next, bb, mode, block,
- readbytes)) != APR_SUCCESS) {
- return rv;
- }
- }
- else {
- APR_BRIGADE_PREPEND(bb, ctx->bb); /* first use the leftovers */
- }
-
- buffer_size = INPUT_XLATE_BUF_SIZE;
- rv = xlate_brigade(ctx, bb, ctx->tmp, &buffer_size, &hit_eos);
- if (rv == APR_SUCCESS) {
- if (!hit_eos) {
- /* move anything leftover into our context for next time;
- * we don't currently "set aside" since the data came from
- * down below, but I suspect that for long-term we need to
- * do that
- */
- APR_BRIGADE_CONCAT(ctx->bb, bb);
- }
- if (buffer_size < INPUT_XLATE_BUF_SIZE) { /* do we have output? */
- apr_bucket *e;
-
- e = apr_bucket_heap_create(ctx->tmp,
- INPUT_XLATE_BUF_SIZE - buffer_size, 1);
- /* make sure we insert at the head, because there may be
- * an eos bucket already there, and the eos bucket should
- * come after the data
- */
- APR_BRIGADE_INSERT_HEAD(bb, e);
- }
- else {
- /* XXX need to get some more data... what if the last brigade
- * we got had only the first byte of a multibyte char? we need
- * to grab more data from the network instead of returning an
- * empty brigade
- */
- }
- }
- else {
- log_xlate_error(f, rv);
- }
-
- return rv;
-}
-
-static const command_rec cmds[] =
-{
- AP_INIT_TAKE1("CharsetSourceEnc",
- add_charset_source,
- NULL,
- OR_FILEINFO,
- "source (html,cgi,ssi) file charset"),
- AP_INIT_TAKE1("CharsetDefault",
- add_charset_default,
- NULL,
- OR_FILEINFO,
- "name of default charset"),
- AP_INIT_ITERATE("CharsetOptions",
- add_charset_options,
- NULL,
- OR_FILEINFO,
- "valid options: ImplicitAdd, NoImplicitAdd, DebugLevel=n"),
- {NULL}
-};
-
-static void charset_register_hooks(apr_pool_t *p)
-{
- ap_hook_fixups(find_code_page, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_insert_filter(xlate_insert_filter, NULL, NULL, APR_HOOK_REALLY_LAST);
- ap_register_output_filter(XLATEOUT_FILTER_NAME, xlate_out_filter,
- AP_FTYPE_RESOURCE);
- ap_register_input_filter(XLATEIN_FILTER_NAME, xlate_in_filter,
- AP_FTYPE_RESOURCE);
-}
-
-module AP_MODULE_DECLARE_DATA charset_lite_module =
-{
- STANDARD20_MODULE_STUFF,
- create_charset_dir_conf,
- merge_charset_dir_conf,
- NULL,
- NULL,
- cmds,
- charset_register_hooks
-};
-
diff --git a/modules/experimental/mod_charset_lite.exp b/modules/experimental/mod_charset_lite.exp
deleted file mode 100644
index 3f0bf14b4a..0000000000
--- a/modules/experimental/mod_charset_lite.exp
+++ /dev/null
@@ -1 +0,0 @@
-charset_lite_module
diff --git a/modules/experimental/mod_deflate.c b/modules/experimental/mod_deflate.c
deleted file mode 100644
index 7744aee1f4..0000000000
--- a/modules/experimental/mod_deflate.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * (zlib functions gz_open and gzwrite)
- */
-
-/*
- * mod_deflate.c: Perform deflate transfer-encoding on the fly
- *
- * Written by Ian Holsman (IanH@apache.org)
- *
- */
-
-#include "httpd.h"
-#include "http_config.h"
-#include "http_log.h"
-#include "apr_strings.h"
-#include "apr_general.h"
-#include "util_filter.h"
-#include "apr_buckets.h"
-#include "http_request.h"
-
-#include "zlib.h"
-
-#ifdef HAVE_ZUTIL_H
-#include "zutil.h"
-#else
-/* As part of the encoding process, we must send what our OS_CODE is
- * (or so it seems based on what I can tell of how gzip encoding works).
- *
- * zutil.h is not always included with zlib distributions (it is a private
- * header), so this is straight from zlib 1.1.3's zutil.h.
- */
-#ifdef OS2
-#define OS_CODE 0x06
-#endif
-
-#ifdef WIN32 /* Window 95 & Windows NT */
-#define OS_CODE 0x0b
-#endif
-
-#if defined(VAXC) || defined(VMS)
-#define OS_CODE 0x02
-#endif
-
-#ifdef AMIGA
-#define OS_CODE 0x01
-#endif
-
-#if defined(ATARI) || defined(atarist)
-#define OS_CODE 0x05
-#endif
-
-#if defined(MACOS) || defined(TARGET_OS_MAC)
-#define OS_CODE 0x07
-#endif
-
-#ifdef __50SERIES /* Prime/PRIMOS */
-#define OS_CODE 0x0F
-#endif
-
-#ifdef TOPS20
-#define OS_CODE 0x0a
-#endif
-
-#ifndef OS_CODE
-#define OS_CODE 0x03 /* assume Unix */
-#endif
-#endif
-
-static const char deflateFilterName[] = "DEFLATE";
-module AP_MODULE_DECLARE_DATA deflate_module;
-
-typedef struct deflate_filter_config_t
-{
- int windowSize;
- int memlevel;
- char *noteName;
-} deflate_filter_config;
-
-/* windowsize is negative to suppress Zlib header */
-#define DEFAULT_WINDOWSIZE -15
-#define DEFAULT_MEMLEVEL 9
-#define FILTER_BUFSIZE 8096
-
-/* Outputs a long in LSB order to the given file
- * only the bottom 4 bits are required for the deflate file format.
- */
-static void putLong(char *string, unsigned long x)
-{
- int n;
- for (n = 0; n < 4; n++) {
- string[n] = (int) (x & 0xff);
- x >>= 8;
- }
-}
-
-static void *create_deflate_server_config(apr_pool_t *p, server_rec *s)
-{
- deflate_filter_config *c = apr_pcalloc(p, sizeof *c);
-
- c->memlevel = DEFAULT_MEMLEVEL;
- c->windowSize = DEFAULT_WINDOWSIZE;
-
- return c;
-}
-
-static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy,
- const char *arg)
-{
- deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
- &deflate_module);
- int i;
-
- i = atoi(arg);
-
- if (i < 1 || i > 15)
- return "DeflateWindowSize must be between 1 and 15";
-
- c->windowSize = i * -1;
-
- return NULL;
-}
-
-static const char *deflate_set_note(cmd_parms *cmd, void *dummy,
- const char *arg)
-{
- deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
- &deflate_module);
- c->noteName = apr_pstrdup(cmd->pool, arg);
-
- return NULL;
-}
-
-static const char *deflate_set_memlevel(cmd_parms *cmd, void *dummy,
- const char *arg)
-{
- deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
- &deflate_module);
- int i;
-
- i = atoi(arg);
-
- if (i < 1 || i > 9)
- return "DeflateMemLevel must be between 1 and 9";
-
- c->memlevel = i;
-
- return NULL;
-}
-
-/* magic header */
-static int deflate_magic[2] = { 0x1f, 0x8b };
-
-typedef struct deflate_ctx_t
-{
- z_stream stream;
- unsigned char buffer[FILTER_BUFSIZE];
- unsigned long crc;
- apr_bucket_brigade *bb;
-} deflate_ctx;
-
-static apr_status_t deflate_out_filter(ap_filter_t *f,
- apr_bucket_brigade *bb)
-{
- apr_bucket *e;
- const char *accepts;
- request_rec *r = f->r;
- deflate_ctx *ctx = f->ctx;
- char *token = NULL;
- int zRC;
- deflate_filter_config *c = ap_get_module_config(r->server->module_config,
- &deflate_module);
-
- /* If we don't have a context, we need to ensure that it is okay to send
- * the deflated content. If we have a context, that means we've done
- * this before and we liked it.
- * This could be not so nice if we always fail. But, if we succeed,
- * we're in better shape.
- */
- if (!ctx) {
- char *buf;
-
- /* only work on main request/no subrequests */
- if (r->main) {
- return ap_pass_brigade(f->next, bb);
- }
-
- /* some browsers might have problems, so set no-gzip
- * (with browsermatch) for them
- */
- if (apr_table_get(r->subprocess_env, "no-gzip")) {
- return ap_pass_brigade(f->next, bb);
- }
-
- /* Some browsers might have problems with content types
- * other than text/html, so set gzip-only-text/html
- * (with browsermatch) for them
- */
- if ((r->content_type == NULL
- || strncmp(r->content_type, "text/html", 9))
- && apr_table_get(r->subprocess_env, "gzip-only-text/html")) {
- return ap_pass_brigade(f->next, bb);
- }
-
- /* if they don't have the line, then they can't play */
- accepts = apr_table_get(r->headers_in, "Accept-Encoding");
- if (accepts == NULL) {
- return ap_pass_brigade(f->next, bb);
- }
-
- token = ap_get_token(r->pool, &accepts, 0);
- while (token && token[0] && strcmp(token, "gzip")) {
- /* skip token */
- accepts++;
- token = ap_get_token(r->pool, &accepts, 0);
- }
-
- /* No acceptable token found. */
- if (token == NULL || token[0] == '\0') {
- return ap_pass_brigade(f->next, bb);
- }
-
- /* We're cool with filtering this. */
- ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
- ctx->bb = apr_brigade_create(f->r->pool);
-/*
- ctx->stream.zalloc = (alloc_func) 0;
- ctx->stream.zfree = (free_func) 0;
- ctx->stream.opaque = (voidpf) 0;
- ctx->crc = 0L;
-*/
- zRC = deflateInit2(&ctx->stream, Z_BEST_SPEED, Z_DEFLATED,
- c->windowSize, c->memlevel,
- Z_DEFAULT_STRATEGY);
-
- if (zRC != Z_OK) {
- f->ctx = NULL;
- ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
- "unable to init Zlib: "
- "deflateInit2 returned %d: URL %s",
- zRC, r->uri);
- return ap_pass_brigade(f->next, bb);
- }
-
- buf = apr_psprintf(r->pool, "%c%c%c%c%c%c%c%c%c%c", deflate_magic[0],
- deflate_magic[1], Z_DEFLATED, 0 /* flags */ , 0, 0,
- 0, 0 /* time */ , 0 /* xflags */ , OS_CODE);
- e = apr_bucket_pool_create(buf, 10, r->pool);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
-
- apr_table_setn(r->headers_out, "Content-Encoding", "gzip");
- apr_table_setn(r->headers_out, "Vary", "Accept-Encoding");
- apr_table_unset(r->headers_out, "Content-Length");
- }
-
- APR_BRIGADE_FOREACH(e, bb) {
- const char *data;
- apr_bucket *b;
- apr_size_t len;
-
- int done = 0;
-
- if (APR_BUCKET_IS_EOS(e)) {
- char *buf, *p;
- char crc_array[4], len_array[4];
- unsigned int deflate_len;
-
- ctx->stream.avail_in = 0; /* should be zero already anyway */
- for (;;) {
- deflate_len = FILTER_BUFSIZE - ctx->stream.avail_out;
-
- if (deflate_len != 0) {
- b = apr_bucket_heap_create((char *)ctx->buffer,
- deflate_len, 1);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
- ctx->stream.next_out = ctx->buffer;
- ctx->stream.avail_out = FILTER_BUFSIZE;
- }
-
- if (done) {
- break;
- }
-
- zRC = deflate(&ctx->stream, Z_FINISH);
-
- if (deflate_len == 0 && zRC == Z_BUF_ERROR) {
- zRC = Z_OK;
- }
-
- done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
-
- if (zRC != Z_OK && zRC != Z_STREAM_END) {
- break;
- }
- }
-
- putLong(crc_array, ctx->crc);
- putLong(len_array, ctx->stream.total_in);
-
- p = buf = apr_palloc(r->pool, 8);
- *p++ = crc_array[0];
- *p++ = crc_array[1];
- *p++ = crc_array[2];
- *p++ = crc_array[3];
- *p++ = len_array[0];
- *p++ = len_array[1];
- *p++ = len_array[2];
- *p++ = len_array[3];
-
- b = apr_bucket_pool_create(buf, 8, r->pool);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r,
- "Zlib: Compressed %ld to %ld : URL %s",
- ctx->stream.total_in, ctx->stream.total_out, r->uri);
-
- if (c->noteName) {
- if (ctx->stream.total_in > 0) {
- int total;
-
- total = ctx->stream.total_out * 100 / ctx->stream.total_in;
-
- apr_table_setn(r->notes, c->noteName,
- apr_itoa(r->pool, total));
- }
- else {
- apr_table_setn(r->notes, c->noteName, "-");
- }
- }
-
- deflateEnd(&ctx->stream);
-
- /* Remove EOS from the old list, and insert into the new. */
- APR_BUCKET_REMOVE(e);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
-
- /* Okay, we've seen the EOS.
- * Time to pass it along down the chain.
- */
- return ap_pass_brigade(f->next, ctx->bb);
- }
-
- if (APR_BUCKET_IS_FLUSH(e)) {
- /* XXX FIX: do we need the Content-Size set, or can we stream?
- * we should be able to stream
- */
-
- /* Ignore flush buckets for the moment.. we can't stream as we
- * need the size ;(
- */
- continue;
- }
-
- /* read */
- apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
-
- /* This crc32 function is from zlib. */
- ctx->crc = crc32(ctx->crc, (const Bytef *)data, len);
-
- /* write */
- ctx->stream.next_in = (unsigned char *)data; /* We just lost const-ness,
- * but we'll just have to
- * trust zlib */
- ctx->stream.avail_in = len;
- ctx->stream.next_out = ctx->buffer;
- ctx->stream.avail_out = FILTER_BUFSIZE;
-
- while (ctx->stream.avail_in != 0) {
- if (ctx->stream.avail_out == 0) {
- ctx->stream.next_out = ctx->buffer;
- len = FILTER_BUFSIZE - ctx->stream.avail_out;
-
- b = apr_bucket_heap_create((char *)ctx->buffer, len, 1);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
- ctx->stream.avail_out = FILTER_BUFSIZE;
- }
-
- zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
-
- if (zRC != Z_OK)
- return APR_EGENERAL;
- }
- }
-
- apr_brigade_destroy(bb);
- return APR_SUCCESS;
-}
-
-static void register_hooks(apr_pool_t *p)
-{
- ap_register_output_filter(deflateFilterName, deflate_out_filter,
- AP_FTYPE_CONTENT_SET);
-}
-
-static const command_rec deflate_filter_cmds[] = {
- AP_INIT_TAKE1("DeflateFilterNote", deflate_set_note, NULL, RSRC_CONF,
- "Set a note to report on compression ratio"),
- AP_INIT_TAKE1("DeflateWindowSize", deflate_set_window_size, NULL,
- RSRC_CONF, "Set the Deflate window size (1-15)"),
- AP_INIT_TAKE1("DeflateMemLevel", deflate_set_memlevel, NULL, RSRC_CONF,
- "Set the Deflate Memory Level (1-9)"),
- {NULL}
-};
-
-module AP_MODULE_DECLARE_DATA deflate_module = {
- STANDARD20_MODULE_STUFF,
- NULL, /* dir config creater */
- NULL, /* dir merger --- default is to override */
- create_deflate_server_config, /* server config */
- NULL, /* merge server config */
- deflate_filter_cmds, /* command table */
- register_hooks /* register hooks */
-};
diff --git a/modules/experimental/mod_deflate.exp b/modules/experimental/mod_deflate.exp
deleted file mode 100644
index 9ec76883cd..0000000000
--- a/modules/experimental/mod_deflate.exp
+++ /dev/null
@@ -1 +0,0 @@
-deflate_module
diff --git a/modules/experimental/mod_disk_cache.c b/modules/experimental/mod_disk_cache.c
deleted file mode 100644
index a06f84ded5..0000000000
--- a/modules/experimental/mod_disk_cache.c
+++ /dev/null
@@ -1,814 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * 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"
-
-#if APR_HAVE_UNISTD_H
-#include <unistd.h> /* needed for unlink/link */
-#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;
- int version; /* update count of the file */
- apr_file_t *fd; /* data file */
- apr_file_t *hfd; /* headers file */
- apr_off_t file_size; /* File size of the cached data file */
-} disk_cache_object_t;
-
-/*
- * mod_disk_cache configuration
- */
-/* TODO: Make defaults OS specific */
-#define CACHEFILE_LEN 20 /* must be less than HASH_LEN/2 */
-#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;
- apr_size_t cache_root_len;
- off_t space; /* Maximum cache size (in 1024 bytes) */
- apr_time_t maxexpire; /* Maximum time to keep cached files in msecs */
- apr_time_t defaultexpire; /* default time to keep cached file in msecs */
- double lmfactor; /* factor for estimating expires date */
- apr_time_t gcinterval; /* garbage collection interval, in msec */
- int dirlevels; /* Number of levels of subdirectories */
- int dirlength; /* Length of subdirectory names */
- int expirychk; /* true if expiry time is observed for cached files */
- apr_size_t minfs; /* minumum file size for cached files */
- apr_size_t maxfs; /* maximum file size for cached files */
- apr_time_t mintm; /* minimum time margin for caching files */
- /* dgc_time_t gcdt; time of day for daily garbage collection */
- apr_array_header_t *gcclnun; /* gc_retain_t entries for unused files */
- apr_array_header_t *gcclean; /* gc_retain_t entries for all files */
- int maxgcmem; /* maximum memory used by garbage collection */
-} disk_cache_conf;
-
-module AP_MODULE_DECLARE_DATA disk_cache_module;
-
-/* Forward declarations */
-static int remove_entity(cache_handle_t *h);
-static apr_status_t write_headers(cache_handle_t *h, request_rec *r, cache_info *i);
-static apr_status_t write_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);
-static apr_status_t read_headers(cache_handle_t *h, request_rec *r);
-static apr_status_t read_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
-
-/*
- * Local static functions
- */
-#define CACHE_HEADER_SUFFIX ".header"
-#define CACHE_DATA_SUFFIX ".data"
-static char *header_file(apr_pool_t *p, int dirlevels, int dirlength,
- const char *root, const char *name)
-{
- char *hashfile;
- hashfile = generate_name(p, dirlevels, dirlength, name);
- return apr_pstrcat(p, root, "/", hashfile, CACHE_HEADER_SUFFIX, NULL);
-}
-
-static char *data_file(apr_pool_t *p, int dirlevels, int dirlength,
- const char *root, const char *name)
-{
- char *hashfile;
- hashfile = generate_name(p, dirlevels, dirlength, name);
- return apr_pstrcat(p, root, "/", hashfile, CACHE_DATA_SUFFIX, NULL);
-}
-
-static void mkdir_structure(disk_cache_conf *conf, char *file, apr_pool_t *pool)
-{
- apr_status_t rv;
- char *p;
-
- for (p = file + conf->cache_root_len + 1;;) {
- p = strchr(p, '/');
- if (!p)
- break;
- *p = '\0';
-
- rv = apr_dir_make(file,
- APR_UREAD|APR_UWRITE|APR_UEXECUTE, pool);
- if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) {
- /* XXX */
- }
- *p = '/';
- ++p;
- }
-}
-
-static apr_status_t file_cache_el_final(cache_handle_t *h, request_rec *r)
-{
- apr_status_t rv;
- disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
- &disk_cache_module);
- disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
-
- /* move the data over */
- if (dobj->fd) {
- apr_file_flush(dobj->fd);
- if (!dobj->datafile) {
- dobj->datafile = data_file(r->pool, conf->dirlevels, conf->dirlength,
- conf->cache_root, h->cache_obj->key);
- }
- /* 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.
- */
- rv = apr_file_remove(dobj->datafile, r->pool);
- if (rv != APR_SUCCESS) {
- mkdir_structure(conf, dobj->datafile, r->pool);
- }
-
- /*
- * This assumes that the tempfile is on the same file system
- * as the cache_root. If not, then we need a file copy/move
- * rather than a rename.
- */
- rv = apr_file_rename(dobj->tempfile, dobj->datafile, r->pool);
- if (rv != APR_SUCCESS) {
- /* XXX log */
- }
-
- apr_file_close(dobj->fd);
- dobj->fd = NULL;
- /* 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
- */
-static int file_cache_read_mydata(apr_file_t *fd, cache_info *info,
- disk_cache_object_t *dobj)
-{
- apr_status_t rv;
- char urlbuff[1034]; /* XXX FIXME... THIS IS A POTENTIAL SECURITY HOLE */
- int urllen = sizeof(urlbuff);
- int offset=0;
- char * temp;
-
- /* read the data from the cache file */
- /* format
- * date SP expire SP count CRLF
- * dates are stored as hex seconds since 1970
- */
- rv = apr_file_gets(&urlbuff[0], urllen, fd);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- if ((temp = strchr(&urlbuff[0], '\n')) != NULL) /* trim off new line character */
- *temp = '\0'; /* overlay it with the null terminator */
-
- if (!apr_date_checkmask(urlbuff, "&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&")) {
- return APR_EGENERAL;
- }
-
- info->date = ap_cache_hex2msec(urlbuff + offset);
- offset += (sizeof(info->date)*2) + 1;
- info->expire = ap_cache_hex2msec(urlbuff + offset);
- offset += (sizeof(info->expire)*2) + 1;
- dobj->version = ap_cache_hex2msec(urlbuff + offset);
-
- /* check that we have the same URL */
- rv = apr_file_gets(&urlbuff[0], urllen, fd);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- if ((temp = strchr(&urlbuff[0], '\n')) != NULL) { /* trim off new line character */
- *temp = '\0'; /* overlay it with the null terminator */
- }
-
- if (strncmp(urlbuff, "X-NAME: ", 7) != 0) {
- return APR_EGENERAL;
- }
- if (strcmp(urlbuff + 8, dobj->name) != 0) {
- return APR_EGENERAL;
- }
-
- return APR_SUCCESS;
-}
-
-static int file_cache_write_mydata(apr_file_t *fd , cache_handle_t *h, request_rec *r)
-{
- apr_status_t rc;
- char *buf;
- apr_size_t amt;
-
- char dateHexS[sizeof(apr_time_t) * 2 + 1];
- char expireHexS[sizeof(apr_time_t) * 2 + 1];
- char verHexS[sizeof(apr_time_t) * 2 + 1];
- cache_info *info = &(h->cache_obj->info);
- disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
-
- if (!r->headers_out) {
- /* XXX log message */
- return 0;
- }
-
- ap_cache_msec2hex(info->date, dateHexS);
- ap_cache_msec2hex(info->expire, expireHexS);
- ap_cache_msec2hex(dobj->version++, verHexS);
- buf = apr_pstrcat(r->pool, dateHexS, " ", expireHexS, " ", verHexS, "\n", NULL);
- amt = strlen(buf);
- rc = apr_file_write(fd, buf, &amt);
- if (rc != APR_SUCCESS) {
- /* XXX log message */
- return 0;
- }
-
- buf = apr_pstrcat(r->pool, "X-NAME: ", dobj->name, "\n", NULL);
- amt = strlen(buf);
- rc = apr_file_write(fd, buf, &amt);
- if (rc != APR_SUCCESS) {
- /* XXX log message */
- return 0;
- }
- return 1;
-}
-
-/*
- * Hook and mod_cache callback functions
- */
-#define AP_TEMPFILE "/aptmpXXXXXX"
-static int create_entity(cache_handle_t *h, request_rec *r,
- const char *type,
- const char *key,
- apr_size_t len)
-{
- disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
- &disk_cache_module);
- apr_status_t rv;
- cache_object_t *obj;
- disk_cache_object_t *dobj;
- apr_file_t *tmpfile;
-
- if (strcasecmp(type, "disk")) {
- return DECLINED;
- }
-
- /* Allocate and initialize cache_object_t and disk_cache_object_t */
- obj = apr_pcalloc(r->pool, sizeof(*obj));
- obj->vobj = dobj = apr_pcalloc(r->pool, sizeof(*dobj));
-
- obj->key = apr_pstrdup(r->pool, key);
- obj->info.len = len;
- obj->complete = 0; /* Cache object is not complete */
-
- dobj->name = obj->key;
-
- /* open temporary file */
- dobj->tempfile = apr_pstrcat(r->pool, conf->cache_root, AP_TEMPFILE, NULL);
- rv = apr_file_mktemp(&tmpfile, dobj->tempfile,
- APR_CREATE | APR_READ | APR_WRITE | APR_EXCL, r->pool);
-
- /* Populate the cache handle */
- h->cache_obj = obj;
- h->read_body = &read_body;
- h->read_headers = &read_headers;
- h->write_body = &write_body;
- h->write_headers = &write_headers;
- h->remove_entity = &remove_entity;
-
- ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r->server,
- "disk_cache: Caching URL %s", key);
-
- return OK;
-}
-
-static int open_entity(cache_handle_t *h, request_rec *r, const char *type, const char *key)
-{
- apr_status_t rc;
- disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
- &disk_cache_module);
- char *data = data_file(r->pool, conf->dirlevels, conf->dirlength,
- conf->cache_root, key);
- char *headers = header_file(r->pool, conf->dirlevels, conf->dirlength,
- conf->cache_root, key);
- apr_file_t *fd;
- apr_file_t *hfd;
- apr_finfo_t finfo;
- cache_object_t *obj;
- cache_info *info;
- disk_cache_object_t *dobj;
-
- h->cache_obj = NULL;
-
- /* Look up entity keyed to 'url' */
- if (strcasecmp(type, "disk")) {
- return DECLINED;
- }
-
- /* Open the data file */
- rc = apr_file_open(&fd, data, APR_READ|APR_BINARY, 0, r->pool);
- if (rc != APR_SUCCESS) {
- /* XXX: Log message */
- return DECLINED;
- }
-
- /* Open the headers file */
- rc = apr_file_open(&hfd, headers, APR_READ|APR_BINARY, 0, r->pool);
- if (rc != APR_SUCCESS) {
- /* XXX: Log message */
- return DECLINED;
- }
-
- /* Create and init the cache object */
- h->cache_obj = obj = apr_pcalloc(r->pool, sizeof(cache_object_t));
- obj->vobj = dobj = apr_pcalloc(r->pool, sizeof(disk_cache_object_t));
-
- info = &(obj->info);
- obj->key = (char *) key;
- dobj->name = (char *) key;
- dobj->fd = fd;
- dobj->hfd = hfd;
- dobj->datafile = data;
- dobj->hdrsfile = headers;
-
- rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, fd);
- if (rc == APR_SUCCESS) {
- dobj->file_size = finfo.size;
- }
-
- /* Read the bytes to setup the cache_info fields */
- rc = file_cache_read_mydata(hfd, info, dobj);
- if (rc != APR_SUCCESS) {
- /* XXX log message */
- return DECLINED;
- }
-
- /* Initialize the cache_handle callback functions */
- h->read_body = &read_body;
- h->read_headers = &read_headers;
- h->write_body = &write_body;
- h->write_headers = &write_headers;
- h->remove_entity = &remove_entity;
-
- ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r->server,
- "disk_cache: Serving Cached URL %s", dobj->name);
- return OK;
-}
-
-static int remove_url(const char *type, char *key)
-{
- return OK;
-}
-
-static int remove_entity(cache_handle_t *h)
-{
- cache_object_t *obj = h->cache_obj;
-
- /* Null out the cache object pointer so next time we start from scratch */
- h->cache_obj = NULL;
- 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?
- */
-static apr_status_t read_headers(cache_handle_t *h, request_rec *r)
-{
- apr_status_t rv;
- char *temp;
- char urlbuff[1034];
- int urllen = sizeof(urlbuff);
- disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
-
- /* This case should not happen... */
- if (!dobj->fd || !dobj->hfd) {
- /* XXX log message */
- return APR_NOTFOUND;
- }
-
- if(!r->headers_out) {
- r->headers_out = apr_table_make(r->pool, 20);
- }
-
- /*
- * Call routine to read the header lines/status line
- */
- ap_scan_script_header_err(r, dobj->hfd, NULL);
-
- apr_table_setn(r->headers_out, "Content-Type",
- ap_make_content_type(r, r->content_type));
-
- rv = apr_file_gets(&urlbuff[0], urllen, dobj->hfd); /* Read status */
- if (rv != APR_SUCCESS) {
- /* XXX log message */
- return rv;
- }
-
- r->status = atoi(urlbuff); /* Save status line into request rec */
-
- rv = apr_file_gets(&urlbuff[0], urllen, dobj->hfd); /* Read status line */
- if (rv != APR_SUCCESS) {
- /* XXX log message */
- return rv;
- }
-
- if ((temp = strchr(&urlbuff[0], '\n')) != NULL) /* trim off new line character */
- *temp = '\0'; /* overlay it with the null terminator */
-
- r->status_line = apr_pstrdup(r->pool, urlbuff); /* Save status line into request rec */
-
- apr_file_close(dobj->hfd);
-
- ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r->server,
- "disk_cache: Served headers for URL %s", dobj->name);
- return APR_SUCCESS;
-}
-
-static apr_status_t read_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb)
-{
- apr_bucket *e;
- disk_cache_object_t *dobj = (disk_cache_object_t*) h->cache_obj->vobj;
-
- e = apr_bucket_file_create(dobj->fd, 0, dobj->file_size, p);
-
- APR_BRIGADE_INSERT_HEAD(bb, e);
- e = apr_bucket_eos_create();
- APR_BRIGADE_INSERT_TAIL(bb, e);
-
- return APR_SUCCESS;
-}
-
-static apr_status_t write_headers(cache_handle_t *h, request_rec *r, cache_info *info)
-{
- disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
- &disk_cache_module);
- apr_status_t rv;
- char *buf;
- char statusbuf[8];
- apr_size_t amt;
- disk_cache_object_t *dobj = (disk_cache_object_t*) h->cache_obj->vobj;
- apr_file_t *hfd = dobj->hfd;
-
- if (!hfd) {
- if (!dobj->hdrsfile) {
- dobj->hdrsfile = header_file(r->pool,
- conf->dirlevels,
- conf->dirlength,
- conf->cache_root,
- h->cache_obj->key);
- }
-
- /* This is flaky... we need to manage the cache_info differently */
- h->cache_obj->info = *info;
-
- /* 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.
- */
- rv = apr_file_remove(dobj->hdrsfile, r->pool);
- if (rv != APR_SUCCESS) {
- mkdir_structure(conf, dobj->hdrsfile, r->pool);
- }
-
- rv = apr_file_open(&dobj->hfd, dobj->hdrsfile,
- APR_WRITE | APR_CREATE | APR_EXCL,
- 0, r->pool);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- hfd = dobj->hfd;
- dobj->name = h->cache_obj->key;
-
- file_cache_write_mydata(dobj->hfd, h, r);
-
- if (r->headers_out) {
- int i;
- apr_table_entry_t *elts = (apr_table_entry_t *) apr_table_elts(r->headers_out)->elts;
- for (i = 0; i < apr_table_elts(r->headers_out)->nelts; ++i) {
- if (elts[i].key != NULL) {
- buf = apr_pstrcat(r->pool, elts[i].key, ": ", elts[i].val, CRLF, NULL);
- amt = strlen(buf);
- apr_file_write(hfd, buf, &amt);
- }
- }
- buf = apr_pstrcat(r->pool, CRLF, NULL);
- amt = strlen(buf);
- apr_file_write(hfd, buf, &amt);
- }
- sprintf(statusbuf,"%d", r->status);
- buf = apr_pstrcat(r->pool, statusbuf, CRLF, NULL);
- amt = strlen(buf);
- apr_file_write(hfd, buf, &amt);
- buf = apr_pstrcat(r->pool, r->status_line, "\n", NULL);
- amt = strlen(buf);
- apr_file_write(hfd, buf, &amt);
- buf = apr_pstrcat(r->pool, CRLF, NULL);
- amt = strlen(buf);
- apr_file_write(hfd, buf, &amt);
- apr_file_close(hfd); /* flush and close */
- }
- else {
- /* XXX log message */
- }
-
- ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r->server,
- "disk_cache: Caching headers for URL %s", dobj->name);
- return APR_SUCCESS;
-}
-static apr_status_t write_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b)
-{
- apr_bucket *e;
- apr_status_t rv;
- disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
- cache_info *info = &(h->cache_obj->info);
-
- if (!dobj->fd) {
- rv = apr_file_open(&dobj->fd, dobj->tempfile,
- APR_WRITE | APR_CREATE | APR_BINARY| APR_TRUNCATE | APR_BUFFERED,
- APR_UREAD | APR_UWRITE, r->pool);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- }
- APR_BRIGADE_FOREACH(e, b) {
- const char *str;
- apr_size_t length;
- apr_bucket_read(e, &str, &length, APR_BLOCK_READ);
- apr_file_write(dobj->fd, str, &length);
- }
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(b))) {
- file_cache_el_final(h, r); /* Link to the perm file, and close the descriptor */
- ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r->server,
- "disk_cache: Cached body for URL %s", dobj->name);
- }
-
- return APR_SUCCESS;
-}
-
-static void *create_config(apr_pool_t *p, server_rec *s)
-{
- disk_cache_conf *conf = apr_pcalloc(p, sizeof(disk_cache_conf));
-
- /* XXX: Set default values */
- conf->dirlevels = DEFAULT_DIRLEVELS;
- conf->dirlength = DEFAULT_DIRLENGTH;
- conf->space = DEFAULT_CACHE_SIZE;
- conf->maxfs = DEFAULT_MAX_FILE_SIZE;
- conf->minfs = DEFAULT_MIN_FILE_SIZE;
-
- conf->cache_root = NULL;
- conf->cache_root_len = 0;
-
- return conf;
-}
-
-/*
- * mod_disk_cache configuration directives handlers.
- */
-static const char
-*set_cache_root(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- conf->cache_root = arg;
- conf->cache_root_len = strlen(arg);
- /* TODO: canonicalize cache_root and strip off any trailing slashes */
-
- return NULL;
-}
-static const char
-*set_cache_size(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- conf->space = atoi(arg);
- return NULL;
-}
-static const char
-*set_cache_gcint(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- 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)
- * filename = "/key % prime1 /key %prime2/key %prime3"
- */
-static const char
-*set_cache_dirlevels(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_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;
-}
-static const char
-*set_cache_dirlength(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_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";
-
- conf->dirlength = val;
- return NULL;
-}
-static const char
-*set_cache_exchk(cmd_parms *parms, void *in_struct_ptr, int flag)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- /* XXX */
- return NULL;
-}
-static const char
-*set_cache_minfs(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- conf->minfs = atoi(arg);
- return NULL;
-}
-static const char
-*set_cache_maxfs(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- conf->maxfs = atoi(arg);
- return NULL;
-}
-static const char
-*set_cache_minetm(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- /* XXX */
- return NULL;
-}
-static const char
-*set_cache_gctime(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- /* XXX */
- return NULL;
-}
-static const char
-*add_cache_gcclean(cmd_parms *parms, void *in_struct_ptr, const char *arg, const char *arg1)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- /* XXX */
- return NULL;
-}
-static const char
-*add_cache_gcclnun(cmd_parms *parms, void *in_struct_ptr, const char *arg, const char *arg1)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- /* XXX */
- return NULL;
-}
-static const char
-*set_cache_maxgcmem(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- disk_cache_conf *conf = ap_get_module_config(parms->server->module_config,
- &disk_cache_module);
- /* XXX */
- return NULL;
-}
-static const command_rec disk_cache_cmds[] =
-{
- AP_INIT_TAKE1("CacheRoot", set_cache_root, NULL, RSRC_CONF,
- "The directory to store cache files"),
- AP_INIT_TAKE1("CacheSize", set_cache_size, NULL, RSRC_CONF,
- "The maximum disk space used by the cache in Kb"),
- AP_INIT_TAKE1("CacheGcInterval", set_cache_gcint, NULL, RSRC_CONF,
- "The interval between garbage collections, in hours"),
- 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_FLAG("CacheExpiryCheck", set_cache_exchk, NULL, RSRC_CONF,
- "on if cache observes Expires date when seeking files"),
- AP_INIT_TAKE1("CacheMinFileSize", set_cache_minfs, NULL, RSRC_CONF,
- "The minimum file size to cache a document"),
- AP_INIT_TAKE1("CacheMaxFileSize", set_cache_maxfs, NULL, RSRC_CONF,
- "The maximum file size to cache a document"),
- AP_INIT_TAKE1("CacheTimeMargin", set_cache_minetm, NULL, RSRC_CONF,
- "The minimum time margin to cache a document"),
- AP_INIT_TAKE1("CacheGcDaily", set_cache_gctime, NULL, RSRC_CONF,
- "The time of day for garbage collection (24 hour clock)"),
- AP_INIT_TAKE2("CacheGcUnused", add_cache_gcclnun, NULL, RSRC_CONF,
- "The time in hours to retain unused file that match a url"),
- AP_INIT_TAKE2("CacheGcClean", add_cache_gcclean, NULL, RSRC_CONF,
- "The time in hours to retain unchanged files that match a url"),
- AP_INIT_TAKE1("CacheGcMemUsage", set_cache_maxgcmem, NULL, RSRC_CONF,
- "The maximum kilobytes of memory used for garbage collection"),
- {NULL}
-};
-
-static void disk_cache_register_hook(apr_pool_t *p)
-{
- /* cache initializer */
- cache_hook_create_entity(create_entity, NULL, NULL, APR_HOOK_MIDDLE);
- cache_hook_open_entity(open_entity, NULL, NULL, APR_HOOK_MIDDLE);
-/* cache_hook_remove_entity(remove_entity, NULL, NULL, APR_HOOK_MIDDLE); */
-}
-
-module AP_MODULE_DECLARE_DATA disk_cache_module = {
- STANDARD20_MODULE_STUFF,
- 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 */
-};
diff --git a/modules/experimental/mod_disk_cache.dsp b/modules/experimental/mod_disk_cache.dsp
deleted file mode 100644
index e7f97cae6f..0000000000
--- a/modules/experimental/mod_disk_cache.dsp
+++ /dev/null
@@ -1,111 +0,0 @@
-# Microsoft Developer Studio Project File - Name="mod_disk_cache" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=mod_disk_cache - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "mod_disk_cache.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "mod_disk_cache.mak" CFG="mod_disk_cache - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_disk_cache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_disk_cache - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "mod_disk_cache - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_DISK_CACHE_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_DISK_CACHE_EXPORTS" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/mod_disk_cache.so"
-
-!ELSEIF "$(CFG)" == "mod_disk_cache - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_DISK_CACHE_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_DISK_CACHE_EXPORTS" /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/mod_disk_cache.so" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "mod_disk_cache - Win32 Release"
-# Name "mod_disk_cache - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\mod_disk_cache.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\mod_cache.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/modules/experimental/mod_example.c b/modules/experimental/mod_example.c
deleted file mode 100644
index 027cadd4c0..0000000000
--- a/modules/experimental/mod_example.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- */
-
-/*
- * Apache example module. Provide demonstrations of how modules do things.
- * It is not meant to be used in a production server. Since it participates
- * in all of the processing phases, it could conceivable interfere with
- * the proper operation of other modules -- particularly the ones related
- * to security.
- *
- * In the interest of brevity, all functions and structures internal to
- * this module, but which may have counterparts in *real* modules, are
- * prefixed with 'x_' instead of 'example_'.
- */
-
-#include "httpd.h"
-#include "http_config.h"
-#include "http_core.h"
-#include "http_log.h"
-#include "http_main.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "util_script.h"
-#include "http_connection.h"
-
-#include "apr_strings.h"
-
-#include <stdio.h>
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* Data declarations. */
-/* */
-/* Here are the static cells and structure declarations private to our */
-/* module. */
-/* */
-/*--------------------------------------------------------------------------*/
-
-/*
- * Sample configuration record. Used for both per-directory and per-server
- * configuration data.
- *
- * It's perfectly reasonable to have two different structures for the two
- * different environments. The same command handlers will be called for
- * both, though, so the handlers need to be able to tell them apart. One
- * possibility is for both structures to start with an int which is 0 for
- * one and 1 for the other.
- *
- * Note that while the per-directory and per-server configuration records are
- * available to most of the module handlers, they should be treated as
- * READ-ONLY by all except the command and merge handlers. Sometimes handlers
- * are handed a record that applies to the current location by implication or
- * inheritance, and modifying it will change the rules for other locations.
- */
-typedef struct x_cfg {
- int cmode; /* Environment to which record applies
- * (directory, server, or combination).
- */
-#define CONFIG_MODE_SERVER 1
-#define CONFIG_MODE_DIRECTORY 2
-#define CONFIG_MODE_COMBO 3 /* Shouldn't ever happen. */
- int local; /* Boolean: "Example" directive declared
- * here?
- */
- int congenital; /* Boolean: did we inherit an "Example"? */
- char *trace; /* Pointer to trace string. */
- char *loc; /* Location to which this record applies. */
-} x_cfg;
-
-/*
- * Let's set up a module-local static cell to point to the accreting callback
- * trace. As each API callback is made to us, we'll tack on the particulars
- * to whatever we've already recorded. To avoid massive memory bloat as
- * directories are walked again and again, we record the routine/environment
- * the first time (non-request context only), and ignore subsequent calls for
- * the same routine/environment.
- */
-static const char *trace = NULL;
-static apr_table_t *static_calls_made = NULL;
-
-/*
- * To avoid leaking memory from pools other than the per-request one, we
- * allocate a module-private pool, and then use a sub-pool of that which gets
- * freed each time we modify the trace. That way previous layers of trace
- * data don't get lost.
- */
-static apr_pool_t *x_pool = NULL;
-static apr_pool_t *x_subpool = NULL;
-
-/*
- * Declare ourselves so the configuration routines can find and know us.
- * We'll fill it in at the end of the module.
- */
-module AP_MODULE_DECLARE_DATA example_module;
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* The following pseudo-prototype declarations illustrate the parameters */
-/* passed to command handlers for the different types of directive */
-/* syntax. If an argument was specified in the directive definition */
-/* (look for "command_rec" below), it's available to the command handler */
-/* via the (void *) info field in the cmd_parms argument passed to the */
-/* handler (cmd->info for the examples below). */
-/* */
-/*--------------------------------------------------------------------------*/
-
-/*
- * Command handler for a NO_ARGS directive. Declared in the command_rec
- * list with
- * AP_INIT_NO_ARGS("directive", function, mconfig, where, help)
- *
- * static const char *handle_NO_ARGS(cmd_parms *cmd, void *mconfig);
- */
-
-/*
- * Command handler for a RAW_ARGS directive. The "args" argument is the text
- * of the commandline following the directive itself. Declared in the
- * command_rec list with
- * AP_INIT_RAW_ARGS("directive", function, mconfig, where, help)
- *
- * static const char *handle_RAW_ARGS(cmd_parms *cmd, void *mconfig,
- * const char *args);
- */
-
-/*
- * Command handler for a FLAG directive. The single parameter is passed in
- * "bool", which is either zero or not for Off or On respectively.
- * Declared in the command_rec list with
- * AP_INIT_FLAG("directive", function, mconfig, where, help)
- *
- * static const char *handle_FLAG(cmd_parms *cmd, void *mconfig, int bool);
- */
-
-/*
- * Command handler for a TAKE1 directive. The single parameter is passed in
- * "word1". Declared in the command_rec list with
- * AP_INIT_TAKE1("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE1(cmd_parms *cmd, void *mconfig,
- * char *word1);
- */
-
-/*
- * Command handler for a TAKE2 directive. TAKE2 commands must always have
- * exactly two arguments. Declared in the command_rec list with
- * AP_INIT_TAKE2("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE2(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2);
- */
-
-/*
- * Command handler for a TAKE3 directive. Like TAKE2, these must have exactly
- * three arguments, or the parser complains and doesn't bother calling us.
- * Declared in the command_rec list with
- * AP_INIT_TAKE3("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE3(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2, char *word3);
- */
-
-/*
- * Command handler for a TAKE12 directive. These can take either one or two
- * arguments.
- * - word2 is a NULL pointer if no second argument was specified.
- * Declared in the command_rec list with
- * AP_INIT_TAKE12("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE12(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2);
- */
-
-/*
- * Command handler for a TAKE123 directive. A TAKE123 directive can be given,
- * as might be expected, one, two, or three arguments.
- * - word2 is a NULL pointer if no second argument was specified.
- * - word3 is a NULL pointer if no third argument was specified.
- * Declared in the command_rec list with
- * AP_INIT_TAKE123("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE123(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2, char *word3);
- */
-
-/*
- * Command handler for a TAKE13 directive. Either one or three arguments are
- * permitted - no two-parameters-only syntax is allowed.
- * - word2 and word3 are NULL pointers if only one argument was specified.
- * Declared in the command_rec list with
- * AP_INIT_TAKE13("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE13(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2, char *word3);
- */
-
-/*
- * Command handler for a TAKE23 directive. At least two and as many as three
- * arguments must be specified.
- * - word3 is a NULL pointer if no third argument was specified.
- * Declared in the command_rec list with
- * AP_INIT_TAKE23("directive", function, mconfig, where, help)
- *
- * static const char *handle_TAKE23(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2, char *word3);
- */
-
-/*
- * Command handler for a ITERATE directive.
- * - Handler is called once for each of n arguments given to the directive.
- * - word1 points to each argument in turn.
- * Declared in the command_rec list with
- * AP_INIT_ITERATE("directive", function, mconfig, where, help)
- *
- * static const char *handle_ITERATE(cmd_parms *cmd, void *mconfig,
- * char *word1);
- */
-
-/*
- * Command handler for a ITERATE2 directive.
- * - Handler is called once for each of the second and subsequent arguments
- * given to the directive.
- * - word1 is the same for each call for a particular directive instance (the
- * first argument).
- * - word2 points to each of the second and subsequent arguments in turn.
- * Declared in the command_rec list with
- * AP_INIT_ITERATE2("directive", function, mconfig, where, help)
- *
- * static const char *handle_ITERATE2(cmd_parms *cmd, void *mconfig,
- * char *word1, char *word2);
- */
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* These routines are strictly internal to this module, and support its */
-/* operation. They are not referenced by any external portion of the */
-/* server. */
-/* */
-/*--------------------------------------------------------------------------*/
-
-/*
- * Locate our directory configuration record for the current request.
- */
-static x_cfg *our_dconfig(const request_rec *r)
-{
- return (x_cfg *) ap_get_module_config(r->per_dir_config, &example_module);
-}
-
-#if 0
-/*
- * Locate our server configuration record for the specified server.
- */
-static x_cfg *our_sconfig(const server_rec *s)
-{
- return (x_cfg *) ap_get_module_config(s->module_config, &example_module);
-}
-
-/*
- * Likewise for our configuration record for the specified request.
- */
-static x_cfg *our_rconfig(const request_rec *r)
-{
- return (x_cfg *) ap_get_module_config(r->request_config, &example_module);
-}
-#endif
-
-/*
- * Likewise for our configuration record for a connection.
- */
-static x_cfg *our_cconfig(const conn_rec *c)
-{
- return (x_cfg *) ap_get_module_config(c->conn_config, &example_module);
-}
-
-/*
- * This routine sets up some module-wide cells if they haven't been already.
- */
-static void setup_module_cells(void)
-{
- /*
- * If we haven't already allocated our module-private pool, do so now.
- */
- if (x_pool == NULL) {
- apr_pool_create(&x_pool, NULL);
- };
- /*
- * Likewise for the table of routine/environment pairs we visit outside of
- * request context.
- */
- if (static_calls_made == NULL) {
- static_calls_made = apr_table_make(x_pool, 16);
- };
-}
-
-/*
- * This routine is used to add a trace of a callback to the list. We're
- * passed the server record (if available), the request record (if available),
- * a pointer to our private configuration record (if available) for the
- * environment to which the callback is supposed to apply, and some text. We
- * turn this into a textual representation and add it to the tail of the list.
- * The list can be displayed by the x_handler() routine.
- *
- * If the call occurs within a request context (i.e., we're passed a request
- * record), we put the trace into the request apr_pool_t and attach it to the
- * request via the notes mechanism. Otherwise, the trace gets added
- * to the static (non-request-specific) list.
- *
- * Note that the r->notes table is only for storing strings; if you need to
- * maintain per-request data of any other type, you need to use another
- * mechanism.
- */
-
-#define TRACE_NOTE "example-trace"
-
-static void trace_add(server_rec *s, request_rec *r, x_cfg *mconfig,
- const char *note)
-{
- const char *sofar;
- char *addon;
- char *where;
- apr_pool_t *p;
- const char *trace_copy;
-
- /*
- * Make sure our pools and tables are set up - we need 'em.
- */
- setup_module_cells();
- /*
- * Now, if we're in request-context, we use the request pool.
- */
- if (r != NULL) {
- p = r->pool;
- if ((trace_copy = apr_table_get(r->notes, TRACE_NOTE)) == NULL) {
- trace_copy = "";
- }
- }
- else {
- /*
- * We're not in request context, so the trace gets attached to our
- * module-wide pool. We do the create/destroy every time we're called
- * in non-request context; this avoids leaking memory in some of
- * the subsequent calls that allocate memory only once (such as the
- * key formation below).
- *
- * Make a new sub-pool and copy any existing trace to it. Point the
- * trace cell at the copied value.
- */
- apr_pool_create(&p, x_pool);
- if (trace != NULL) {
- trace = apr_pstrdup(p, trace);
- }
- /*
- * Now, if we have a sub-pool from before, nuke it and replace with
- * the one we just allocated.
- */
- if (x_subpool != NULL) {
- apr_pool_destroy(x_subpool);
- }
- x_subpool = p;
- trace_copy = trace;
- }
- /*
- * If we weren't passed a configuration record, we can't figure out to
- * what location this call applies. This only happens for co-routines
- * that don't operate in a particular directory or server context. If we
- * got a valid record, extract the location (directory or server) to which
- * it applies.
- */
- where = (mconfig != NULL) ? mconfig->loc : "nowhere";
- where = (where != NULL) ? where : "";
- /*
- * Now, if we're not in request context, see if we've been called with
- * this particular combination before. The apr_table_t is allocated in the
- * module's private pool, which doesn't get destroyed.
- */
- if (r == NULL) {
- char *key;
-
- key = apr_pstrcat(p, note, ":", where, NULL);
- if (apr_table_get(static_calls_made, key) != NULL) {
- /*
- * Been here, done this.
- */
- return;
- }
- else {
- /*
- * First time for this combination of routine and environment -
- * log it so we don't do it again.
- */
- apr_table_set(static_calls_made, key, "been here");
- }
- }
- addon = apr_pstrcat(p,
- " <li>\n"
- " <dl>\n"
- " <dt><samp>", note, "</samp></dt>\n"
- " <dd><samp>[", where, "]</samp></dd>\n"
- " </dl>\n"
- " </li>\n",
- NULL);
- sofar = (trace_copy == NULL) ? "" : trace_copy;
- trace_copy = apr_pstrcat(p, sofar, addon, NULL);
- if (r != NULL) {
- apr_table_set(r->notes, TRACE_NOTE, trace_copy);
- }
- else {
- trace = trace_copy;
- }
- /*
- * You *could* change the following if you wanted to see the calling
- * sequence reported in the server's error_log, but beware - almost all of
- * these co-routines are called for every single request, and the impact
- * on the size (and readability) of the error_log is considerable.
- */
-#define EXAMPLE_LOG_EACH 0
- if (EXAMPLE_LOG_EACH && (s != NULL)) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_example: %s", note);
- }
-}
-
-/*--------------------------------------------------------------------------*/
-/* We prototyped the various syntax for command handlers (routines that */
-/* are called when the configuration parser detects a directive declared */
-/* by our module) earlier. Now we actually declare a "real" routine that */
-/* will be invoked by the parser when our "real" directive is */
-/* encountered. */
-/* */
-/* If a command handler encounters a problem processing the directive, it */
-/* signals this fact by returning a non-NULL pointer to a string */
-/* describing the problem. */
-/* */
-/* The magic return value DECLINE_CMD is used to deal with directives */
-/* that might be declared by multiple modules. If the command handler */
-/* returns NULL, the directive was processed; if it returns DECLINE_CMD, */
-/* the next module (if any) that declares the directive is given a chance */
-/* at it. If it returns any other value, it's treated as the text of an */
-/* error message. */
-/*--------------------------------------------------------------------------*/
-/*
- * Command handler for the NO_ARGS "Example" directive. All we do is mark the
- * call in the trace log, and flag the applicability of the directive to the
- * current location in that location's configuration record.
- */
-static const char *cmd_example(cmd_parms *cmd, void *mconfig)
-{
- x_cfg *cfg = (x_cfg *) mconfig;
-
- /*
- * "Example Wuz Here"
- */
- cfg->local = 1;
- trace_add(cmd->server, NULL, cfg, "cmd_example()");
- return NULL;
-}
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* Now we declare our content handlers, which are invoked when the server */
-/* encounters a document which our module is supposed to have a chance to */
-/* see. (See mod_mime's SetHandler and AddHandler directives, and the */
-/* mod_info and mod_status examples, for more details.) */
-/* */
-/* Since content handlers are dumping data directly into the connexion */
-/* (using the r*() routines, such as rputs() and rprintf()) without */
-/* intervention by other parts of the server, they need to make */
-/* sure any accumulated HTTP headers are sent first. This is done by */
-/* calling send_http_header(). Otherwise, no header will be sent at all, */
-/* and the output sent to the client will actually be HTTP-uncompliant. */
-/*--------------------------------------------------------------------------*/
-/*
- * Sample content handler. All this does is display the call list that has
- * been built up so far.
- *
- * The return value instructs the caller concerning what happened and what to
- * do next:
- * OK ("we did our thing")
- * DECLINED ("this isn't something with which we want to get involved")
- * HTTP_mumble ("an error status should be reported")
- */
-static int x_handler(request_rec *r)
-{
- x_cfg *dcfg;
-
- if (strcmp(r->handler, "example-handler")) {
- return DECLINED;
- }
-
- dcfg = our_dconfig(r);
- trace_add(r->server, r, dcfg, "x_handler()");
- /*
- * We're about to start sending content, so we need to force the HTTP
- * headers to be sent at this point. Otherwise, no headers will be sent
- * at all. We can set any we like first, of course. **NOTE** Here's
- * where you set the "Content-type" header, and you do so by putting it in
- * r->content_type, *not* r->headers_out("Content-type"). If you don't
- * set it, it will be filled in with the server's default type (typically
- * "text/plain"). You *must* also ensure that r->content_type is lower
- * case.
- *
- * We also need to start a timer so the server can know if the connexion
- * is broken.
- */
- r->content_type = "text/html";
- /*
- * If we're only supposed to send header information (HEAD request), we're
- * already there.
- */
- if (r->header_only) {
- return OK;
- }
-
- /*
- * Now send our actual output. Since we tagged this as being
- * "text/html", we need to embed any HTML.
- */
- ap_rputs(DOCTYPE_HTML_3_2, r);
- ap_rputs("<HTML>\n", r);
- ap_rputs(" <HEAD>\n", r);
- ap_rputs(" <TITLE>mod_example Module Content-Handler Output\n", r);
- ap_rputs(" </TITLE>\n", r);
- ap_rputs(" </HEAD>\n", r);
- ap_rputs(" <BODY>\n", r);
- ap_rputs(" <H1><SAMP>mod_example</SAMP> Module Content-Handler Output\n", r);
- ap_rputs(" </H1>\n", r);
- ap_rputs(" <P>\n", r);
- ap_rprintf(r, " Apache HTTP Server version: \"%s\"\n",
- ap_get_server_version());
- ap_rputs(" <BR>\n", r);
- ap_rprintf(r, " Server built: \"%s\"\n", ap_get_server_built());
- ap_rputs(" </P>\n", r);;
- ap_rputs(" <P>\n", r);
- ap_rputs(" The format for the callback trace is:\n", r);
- ap_rputs(" </P>\n", r);
- ap_rputs(" <DL>\n", r);
- ap_rputs(" <DT><EM>n</EM>.<SAMP>&lt;routine-name&gt;", r);
- ap_rputs("(&lt;routine-data&gt;)</SAMP>\n", r);
- ap_rputs(" </DT>\n", r);
- ap_rputs(" <DD><SAMP>[&lt;applies-to&gt;]</SAMP>\n", r);
- ap_rputs(" </DD>\n", r);
- ap_rputs(" </DL>\n", r);
- ap_rputs(" <P>\n", r);
- ap_rputs(" The <SAMP>&lt;routine-data&gt;</SAMP> is supplied by\n", r);
- ap_rputs(" the routine when it requests the trace,\n", r);
- ap_rputs(" and the <SAMP>&lt;applies-to&gt;</SAMP> is extracted\n", r);
- ap_rputs(" from the configuration record at the time of the trace.\n", r);
- ap_rputs(" <STRONG>SVR()</STRONG> indicates a server environment\n", r);
- ap_rputs(" (blank means the main or default server, otherwise it's\n", r);
- ap_rputs(" the name of the VirtualHost); <STRONG>DIR()</STRONG>\n", r);
- ap_rputs(" indicates a location in the URL or filesystem\n", r);
- ap_rputs(" namespace.\n", r);
- ap_rputs(" </P>\n", r);
- ap_rprintf(r, " <H2>Static callbacks so far:</H2>\n <OL>\n%s </OL>\n",
- trace);
- ap_rputs(" <H2>Request-specific callbacks so far:</H2>\n", r);
- ap_rprintf(r, " <OL>\n%s </OL>\n", apr_table_get(r->notes, TRACE_NOTE));
- ap_rputs(" <H2>Environment for <EM>this</EM> call:</H2>\n", r);
- ap_rputs(" <UL>\n", r);
- ap_rprintf(r, " <LI>Applies-to: <SAMP>%s</SAMP>\n </LI>\n", dcfg->loc);
- ap_rprintf(r, " <LI>\"Example\" directive declared here: %s\n </LI>\n",
- (dcfg->local ? "YES" : "NO"));
- ap_rprintf(r, " <LI>\"Example\" inherited: %s\n </LI>\n",
- (dcfg->congenital ? "YES" : "NO"));
- ap_rputs(" </UL>\n", r);
- ap_rputs(" </BODY>\n", r);
- ap_rputs("</HTML>\n", r);
- /*
- * We're all done, so cancel the timeout we set. Since this is probably
- * the end of the request we *could* assume this would be done during
- * post-processing - but it's possible that another handler might be
- * called and inherit our outstanding timer. Not good; to each its own.
- */
- /*
- * We did what we wanted to do, so tell the rest of the server we
- * succeeded.
- */
- return OK;
-}
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* Now let's declare routines for each of the callback phase in order. */
-/* (That's the order in which they're listed in the callback list, *not */
-/* the order in which the server calls them! See the command_rec */
-/* declaration near the bottom of this file.) Note that these may be */
-/* called for situations that don't relate primarily to our function - in */
-/* other words, the fixup handler shouldn't assume that the request has */
-/* to do with "example" stuff. */
-/* */
-/* With the exception of the content handler, all of our routines will be */
-/* called for each request, unless an earlier handler from another module */
-/* aborted the sequence. */
-/* */
-/* Handlers that are declared as "int" can return the following: */
-/* */
-/* OK Handler accepted the request and did its thing with it. */
-/* DECLINED Handler took no action. */
-/* HTTP_mumble Handler looked at request and found it wanting. */
-/* */
-/* What the server does after calling a module handler depends upon the */
-/* handler's return value. In all cases, if the handler returns */
-/* DECLINED, the server will continue to the next module with an handler */
-/* for the current phase. However, if the handler return a non-OK, */
-/* non-DECLINED status, the server aborts the request right there. If */
-/* the handler returns OK, the server's next action is phase-specific; */
-/* see the individual handler comments below for details. */
-/* */
-/*--------------------------------------------------------------------------*/
-/*
- * This function is called during server initialisation. Any information
- * that needs to be recorded must be in static cells, since there's no
- * configuration record.
- *
- * There is no return value.
- */
-
-/*
- * This function is called when an heavy-weight process (such as a child) is
- * being run down or destroyed. As with the child initialisation function,
- * any information that needs to be recorded must be in static cells, since
- * there's no configuration record.
- *
- * There is no return value.
- */
-
-/*
- * This function is called during server initialisation when an heavy-weight
- * process (such as a child) is being initialised. As with the
- * module initialisation function, any information that needs to be recorded
- * must be in static cells, since there's no configuration record.
- *
- * There is no return value.
- */
-
-/*
- * This function gets called to create a per-directory configuration
- * record. This will be called for the "default" server environment, and for
- * each directory for which the parser finds any of our directives applicable.
- * If a directory doesn't have any of our directives involved (i.e., they
- * aren't in the .htaccess file, or a <Location>, <Directory>, or related
- * block), this routine will *not* be called - the configuration for the
- * closest ancestor is used.
- *
- * The return value is a pointer to the created module-specific
- * structure.
- */
-static void *x_create_dir_config(apr_pool_t *p, char *dirspec)
-{
- x_cfg *cfg;
- char *dname = dirspec;
-
- /*
- * Allocate the space for our record from the pool supplied.
- */
- cfg = (x_cfg *) apr_pcalloc(p, sizeof(x_cfg));
- /*
- * Now fill in the defaults. If there are any `parent' configuration
- * records, they'll get merged as part of a separate callback.
- */
- cfg->local = 0;
- cfg->congenital = 0;
- cfg->cmode = CONFIG_MODE_DIRECTORY;
- /*
- * Finally, add our trace to the callback list.
- */
- dname = (dname != NULL) ? dname : "";
- cfg->loc = apr_pstrcat(p, "DIR(", dname, ")", NULL);
- trace_add(NULL, NULL, cfg, "x_create_dir_config()");
- return (void *) cfg;
-}
-
-/*
- * This function gets called to merge two per-directory configuration
- * records. This is typically done to cope with things like .htaccess files
- * or <Location> directives for directories that are beneath one for which a
- * configuration record was already created. The routine has the
- * responsibility of creating a new record and merging the contents of the
- * other two into it appropriately. If the module doesn't declare a merge
- * routine, the record for the closest ancestor location (that has one) is
- * used exclusively.
- *
- * The routine MUST NOT modify any of its arguments!
- *
- * The return value is a pointer to the created module-specific structure
- * containing the merged values.
- */
-static void *x_merge_dir_config(apr_pool_t *p, void *parent_conf,
- void *newloc_conf)
-{
-
- x_cfg *merged_config = (x_cfg *) apr_pcalloc(p, sizeof(x_cfg));
- x_cfg *pconf = (x_cfg *) parent_conf;
- x_cfg *nconf = (x_cfg *) newloc_conf;
- char *note;
-
- /*
- * Some things get copied directly from the more-specific record, rather
- * than getting merged.
- */
- merged_config->local = nconf->local;
- merged_config->loc = apr_pstrdup(p, nconf->loc);
- /*
- * Others, like the setting of the `congenital' flag, get ORed in. The
- * setting of that particular flag, for instance, is TRUE if it was ever
- * true anywhere in the upstream configuration.
- */
- merged_config->congenital = (pconf->congenital | pconf->local);
- /*
- * If we're merging records for two different types of environment (server
- * and directory), mark the new record appropriately. Otherwise, inherit
- * the current value.
- */
- merged_config->cmode =
- (pconf->cmode == nconf->cmode) ? pconf->cmode : CONFIG_MODE_COMBO;
- /*
- * Now just record our being called in the trace list. Include the
- * locations we were asked to merge.
- */
- note = apr_pstrcat(p, "x_merge_dir_config(\"", pconf->loc, "\",\"",
- nconf->loc, "\")", NULL);
- trace_add(NULL, NULL, merged_config, note);
- return (void *) merged_config;
-}
-
-/*
- * This function gets called to create a per-server configuration
- * record. It will always be called for the "default" server.
- *
- * The return value is a pointer to the created module-specific
- * structure.
- */
-static void *x_create_server_config(apr_pool_t *p, server_rec *s)
-{
-
- x_cfg *cfg;
- char *sname = s->server_hostname;
-
- /*
- * As with the x_create_dir_config() reoutine, we allocate and fill
- * in an empty record.
- */
- cfg = (x_cfg *) apr_pcalloc(p, sizeof(x_cfg));
- cfg->local = 0;
- cfg->congenital = 0;
- cfg->cmode = CONFIG_MODE_SERVER;
- /*
- * Note that we were called in the trace list.
- */
- sname = (sname != NULL) ? sname : "";
- cfg->loc = apr_pstrcat(p, "SVR(", sname, ")", NULL);
- trace_add(s, NULL, cfg, "x_create_server_config()");
- return (void *) cfg;
-}
-
-/*
- * This function gets called to merge two per-server configuration
- * records. This is typically done to cope with things like virtual hosts and
- * the default server configuration The routine has the responsibility of
- * creating a new record and merging the contents of the other two into it
- * appropriately. If the module doesn't declare a merge routine, the more
- * specific existing record is used exclusively.
- *
- * The routine MUST NOT modify any of its arguments!
- *
- * The return value is a pointer to the created module-specific structure
- * containing the merged values.
- */
-static void *x_merge_server_config(apr_pool_t *p, void *server1_conf,
- void *server2_conf)
-{
-
- x_cfg *merged_config = (x_cfg *) apr_pcalloc(p, sizeof(x_cfg));
- x_cfg *s1conf = (x_cfg *) server1_conf;
- x_cfg *s2conf = (x_cfg *) server2_conf;
- char *note;
-
- /*
- * Our inheritance rules are our own, and part of our module's semantics.
- * Basically, just note whence we came.
- */
- merged_config->cmode =
- (s1conf->cmode == s2conf->cmode) ? s1conf->cmode : CONFIG_MODE_COMBO;
- merged_config->local = s2conf->local;
- merged_config->congenital = (s1conf->congenital | s1conf->local);
- merged_config->loc = apr_pstrdup(p, s2conf->loc);
- /*
- * Trace our call, including what we were asked to merge.
- */
- note = apr_pstrcat(p, "x_merge_server_config(\"", s1conf->loc, "\",\"",
- s2conf->loc, "\")", NULL);
- trace_add(NULL, NULL, merged_config, note);
- return (void *) merged_config;
-}
-
-/*
- * This routine is called before the server processes the configuration
- * files. There is no return value.
- */
-static int x_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
- apr_pool_t *ptemp)
-{
- /*
- * Log the call and exit.
- */
- trace_add(NULL, NULL, NULL, "x_pre_config()");
-
- return OK;
-}
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static int x_post_config(apr_pool_t *pconf, apr_pool_t *plog,
- apr_pool_t *ptemp, server_rec *s)
-{
- /*
- * Log the call and exit.
- */
- trace_add(NULL, NULL, NULL, "x_post_config()");
- return OK;
-}
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static int x_open_logs(apr_pool_t *pconf, apr_pool_t *plog,
- apr_pool_t *ptemp, server_rec *s)
-{
- /*
- * Log the call and exit.
- */
- trace_add(s, NULL, NULL, "x_open_logs()");
- return OK;
-}
-
-/*
- * All our process-death routine does is add its trace to the log.
- */
-static apr_status_t x_child_exit(void *data)
-{
- char *note;
- server_rec *s = data;
- char *sname = s->server_hostname;
-
- /*
- * The arbitrary text we add to our trace entry indicates for which server
- * we're being called.
- */
- sname = (sname != NULL) ? sname : "";
- note = apr_pstrcat(s->process->pool, "x_child_exit(", sname, ")", NULL);
- trace_add(s, NULL, NULL, note);
- return APR_SUCCESS;
-}
-
-/*
- * All our process initialiser does is add its trace to the log.
- */
-static void x_child_init(apr_pool_t *p, server_rec *s)
-{
- char *note;
- char *sname = s->server_hostname;
-
- /*
- * Set up any module cells that ought to be initialised.
- */
- setup_module_cells();
- /*
- * The arbitrary text we add to our trace entry indicates for which server
- * we're being called.
- */
- sname = (sname != NULL) ? sname : "";
- note = apr_pstrcat(p, "x_child_init(", sname, ")", NULL);
- trace_add(s, NULL, NULL, note);
-
- apr_pool_cleanup_register(p, s, x_child_exit, x_child_exit);
-}
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-#if 0
-static const char *x_http_method(const request_rec *r)
-{
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call and exit.
- */
- trace_add(r->server, NULL, cfg, "x_post_config()");
- return "foo";
-}
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static apr_port_t x_default_port(const request_rec *r)
-{
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call and exit.
- */
- trace_add(r->server, NULL, cfg, "x_post_config()");
- return 80;
-}
-#endif /*0*/
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static void x_insert_filter(request_rec *r)
-{
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call and exit.
- */
- trace_add(r->server, NULL, cfg, "x_post_config()");
-}
-
-/*
- * XXX fix my comment!!!!!! this sounds like the comment for a fixup
- * handler
- *
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static int x_quick_handler(request_rec *r)
-{
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call and exit.
- */
- trace_add(r->server, NULL, cfg, "x_post_config()");
- return DECLINED;
-}
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static int x_pre_connection(conn_rec *c, void *csd)
-{
- x_cfg *cfg;
-
- cfg = our_cconfig(c);
-#if 0
- /*
- * Log the call and exit.
- */
- trace_add(r->server, NULL, cfg, "x_post_config()");
-#endif
- return OK;
-}
-
-/*
- * This routine is called after the request has been read but before any other
- * phases have been processed. This allows us to make decisions based upon
- * the input header fields.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
- * further modules are called for this phase.
- */
-static int x_post_read_request(request_rec *r)
-{
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * We don't actually *do* anything here, except note the fact that we were
- * called.
- */
- trace_add(r->server, r, cfg, "x_post_read_request()");
- return DECLINED;
-}
-
-/*
- * This routine gives our module an opportunity to translate the URI into an
- * actual filename. If we don't do anything special, the server's default
- * rules (Alias directives and the like) will continue to be followed.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
- * further modules are called for this phase.
- */
-static int x_translate_handler(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * We don't actually *do* anything here, except note the fact that we were
- * called.
- */
- trace_add(r->server, r, cfg, "x_translate_handler()");
- return DECLINED;
-}
-
-/*
- * This routine is called to check the authentication information sent with
- * the request (such as looking up the user in a database and verifying that
- * the [encrypted] password sent matches the one in the database).
- *
- * The return value is OK, DECLINED, or some HTTP_mumble error (typically
- * HTTP_UNAUTHORIZED). If we return OK, no other modules are given a chance
- * at the request during this phase.
- */
-static int x_check_user_id(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Don't do anything except log the call.
- */
- trace_add(r->server, r, cfg, "x_check_user_id()");
- return DECLINED;
-}
-
-/*
- * This routine is called to check to see if the resource being requested
- * requires authorisation.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
- * other modules are called during this phase.
- *
- * If *all* modules return DECLINED, the request is aborted with a server
- * error.
- */
-static int x_auth_checker(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call and return OK, or access will be denied (even though we
- * didn't actually do anything).
- */
- trace_add(r->server, r, cfg, "x_auth_checker()");
- return DECLINED;
-}
-
-/*
- * This routine is called to check for any module-specific restrictions placed
- * upon the requested resource. (See the mod_access module for an example.)
- *
- * The return value is OK, DECLINED, or HTTP_mumble. All modules with an
- * handler for this phase are called regardless of whether their predecessors
- * return OK or DECLINED. The first one to return any other status, however,
- * will abort the sequence (and the request) as usual.
- */
-static int x_access_checker(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- trace_add(r->server, r, cfg, "x_access_checker()");
- return DECLINED;
-}
-
-/*
- * This routine is called to determine and/or set the various document type
- * information bits, like Content-type (via r->content_type), language, et
- * cetera.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, no
- * further modules are given a chance at the request for this phase.
- */
-static int x_type_checker(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call, but don't do anything else - and report truthfully that
- * we didn't do anything.
- */
- trace_add(r->server, r, cfg, "x_type_checker()");
- return DECLINED;
-}
-
-/*
- * This routine is called to perform any module-specific fixing of header
- * fields, et cetera. It is invoked just before any content-handler.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, the
- * server will still call any remaining modules with an handler for this
- * phase.
- */
-static int x_fixer_upper(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- /*
- * Log the call and exit.
- */
- trace_add(r->server, r, cfg, "x_fixer_upper()");
- return OK;
-}
-
-/*
- * This routine is called to perform any module-specific logging activities
- * over and above the normal server things.
- *
- * The return value is OK, DECLINED, or HTTP_mumble. If we return OK, any
- * remaining modules with an handler for this phase will still be called.
- */
-static int x_logger(request_rec *r)
-{
-
- x_cfg *cfg;
-
- cfg = our_dconfig(r);
- trace_add(r->server, r, cfg, "x_logger()");
- return DECLINED;
-}
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* Which functions are responsible for which hooks in the server. */
-/* */
-/*--------------------------------------------------------------------------*/
-/*
- * Each function our module provides to handle a particular hook is
- * specified here. The functions are registered using
- * ap_hook_foo(name, predecessors, successors, position)
- * where foo is the name of the hook.
- *
- * The args are as follows:
- * name -> the name of the function to call.
- * predecessors -> a list of modules whose calls to this hook must be
- * invoked before this module.
- * successors -> a list of modules whose calls to this hook must be
- * invoked after this module.
- * position -> The relative position of this module. One of
- * APR_HOOK_FIRST, APR_HOOK_MIDDLE, or APR_HOOK_LAST.
- * Most modules will use APR_HOOK_MIDDLE. If multiple
- * modules use the same relative position, Apache will
- * determine which to call first.
- * If your module relies on another module to run first,
- * or another module running after yours, use the
- * predecessors and/or successors.
- *
- * The number in brackets indicates the order in which the routine is called
- * during request processing. Note that not all routines are necessarily
- * called (such as if a resource doesn't have access restrictions).
- * The actual delivery of content to the browser [9] is not handled by
- * a hook; see the handler declarations below.
- */
-static void x_register_hooks(apr_pool_t *p)
-{
- ap_hook_pre_config(x_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_post_config(x_post_config, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_open_logs(x_open_logs, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_child_init(x_child_init, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_handler(x_handler, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_quick_handler(x_quick_handler, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_pre_connection(x_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
-/* This module doesn't have a process connection phase, but I am leaving
- * the code in, in-case somebody wants to add one.
- */
-/* ap_hook_process_connection(x_fixer_upper, NULL, NULL, APR_HOOK_MIDDLE); */
- /* [1] post read_request handling */
- ap_hook_post_read_request(x_post_read_request, NULL, NULL,
- APR_HOOK_MIDDLE);
- ap_hook_log_transaction(x_logger, NULL, NULL, APR_HOOK_MIDDLE);
-#if 0
- ap_hook_http_method(x_http_method, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_default_port(x_default_port, NULL, NULL, APR_HOOK_MIDDLE);
-#endif
- ap_hook_translate_name(x_translate_handler, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_check_user_id(x_check_user_id, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_fixups(x_fixer_upper, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_type_checker(x_type_checker, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_access_checker(x_access_checker, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_auth_checker(x_auth_checker, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_insert_filter(x_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);
-}
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* All of the routines have been declared now. Here's the list of */
-/* directives specific to our module, and information about where they */
-/* may appear and how the command parser should pass them to us for */
-/* processing. Note that care must be taken to ensure that there are NO */
-/* collisions of directive names between modules. */
-/* */
-/*--------------------------------------------------------------------------*/
-/*
- * List of directives specific to our module.
- */
-static const command_rec x_cmds[] =
-{
- AP_INIT_NO_ARGS(
- "Example", /* directive name */
- cmd_example, /* config action routine */
- NULL, /* argument to include in call */
- OR_OPTIONS, /* where available */
- "Example directive - no arguments" /* directive description */
- ),
- {NULL}
-};
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* Now the list of content handlers available from this module. */
-/* */
-/*--------------------------------------------------------------------------*/
-/*
- * List of content handlers our module supplies. Each handler is defined by
- * two parts: a name by which it can be referenced (such as by
- * {Add,Set}Handler), and the actual routine name. The list is terminated by
- * a NULL block, since it can be of variable length.
- *
- * Note that content-handlers are invoked on a most-specific to least-specific
- * basis; that is, a handler that is declared for "text/plain" will be
- * invoked before one that was declared for "text / *". Note also that
- * if a content-handler returns anything except DECLINED, no other
- * content-handlers will be called.
- */
-#if 0
-static const handler_rec x_handlers[] =
-{
- {"example-handler", x_handler},
- {NULL}
-};
-#endif
-
-/*--------------------------------------------------------------------------*/
-/* */
-/* Finally, the list of callback routines and data structures that provide */
-/* the static hooks into our module from the other parts of the server. */
-/* */
-/*--------------------------------------------------------------------------*/
-/*
- * Module definition for configuration. If a particular callback is not
- * needed, replace its routine name below with the word NULL.
- */
-module AP_MODULE_DECLARE_DATA example_module =
-{
- STANDARD20_MODULE_STUFF,
- x_create_dir_config, /* per-directory config creator */
- x_merge_dir_config, /* dir config merger */
- x_create_server_config, /* server config creator */
- x_merge_server_config, /* server config merger */
- x_cmds, /* command table */
- x_register_hooks, /* set up other request processing hooks */
-};
diff --git a/modules/experimental/mod_ext_filter.c b/modules/experimental/mod_ext_filter.c
deleted file mode 100644
index f425b5b352..0000000000
--- a/modules/experimental/mod_ext_filter.c
+++ /dev/null
@@ -1,794 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-/*
- * mod_ext_filter allows Unix-style filters to filter http content.
- */
-
-#include "httpd.h"
-#include "http_config.h"
-#include "http_log.h"
-#define CORE_PRIVATE
-#include "http_core.h"
-#include "apr_buckets.h"
-#include "util_filter.h"
-#include "apr_strings.h"
-#include "apr_hash.h"
-#include "apr_lib.h"
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-
-typedef struct ef_server_t {
- apr_pool_t *p;
- apr_hash_t *h;
-} ef_server_t;
-
-typedef struct ef_filter_t {
- const char *name;
- enum {INPUT_FILTER=1, OUTPUT_FILTER} mode;
- const char *command;
- int numArgs;
- char *args[30];
- const char *intype; /* list of IMTs we process (well, just one for now) */
-#define INTYPE_ALL (char *)1
- const char *outtype; /* IMT of filtered output */
-#define OUTTYPE_UNCHANGED (char *)1
- int preserves_content_length;
-} ef_filter_t;
-
-typedef struct ef_dir_t {
- int debug;
- int log_stderr;
-} ef_dir_t;
-
-typedef struct ef_ctx_t {
- apr_pool_t *p;
- apr_proc_t *proc;
- apr_procattr_t *procattr;
- ef_dir_t *dc;
- ef_filter_t *filter;
- int noop;
-#if APR_FILES_AS_SOCKETS
- apr_pollfd_t *pollset;
-#endif
-} ef_ctx_t;
-
-module AP_MODULE_DECLARE_DATA ext_filter_module;
-
-static apr_status_t ef_output_filter(ap_filter_t *, apr_bucket_brigade *);
-
-#define DBGLVL_SHOWOPTIONS 1
-#define DBGLVL_GORY 9
-
-static void *create_ef_dir_conf(apr_pool_t *p, char *dummy)
-{
- ef_dir_t *dc = (ef_dir_t *)apr_pcalloc(p, sizeof(ef_dir_t));
-
- dc->debug = -1;
- dc->log_stderr = -1;
-
- return dc;
-}
-
-static void *create_ef_server_conf(apr_pool_t *p, server_rec *s)
-{
- ef_server_t *conf;
-
- conf = (ef_server_t *)apr_pcalloc(p, sizeof(ef_server_t));
- conf->p = p;
- conf->h = apr_hash_make(conf->p);
- return conf;
-}
-
-static void *merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
-{
- ef_dir_t *a = (ef_dir_t *)apr_pcalloc (p, sizeof(ef_dir_t));
- ef_dir_t *base = (ef_dir_t *)basev, *over = (ef_dir_t *)overridesv;
-
- if (over->debug != -1) { /* if admin coded something... */
- a->debug = over->debug;
- }
- else {
- a->debug = base->debug;
- }
-
- if (over->log_stderr != -1) { /* if admin coded something... */
- a->log_stderr = over->log_stderr;
- }
- else {
- a->log_stderr = base->log_stderr;
- }
-
- return a;
-}
-
-static const char *add_options(cmd_parms *cmd, void *in_dc,
- const char *arg)
-{
- ef_dir_t *dc = in_dc;
-
- if (!strncasecmp(arg, "DebugLevel=", 11)) {
- dc->debug = atoi(arg + 11);
- }
- else if (!strcasecmp(arg, "LogStderr")) {
- dc->log_stderr = 1;
- }
- else if (!strcasecmp(arg, "NoLogStderr")) {
- dc->log_stderr = 0;
- }
- else {
- return apr_pstrcat(cmd->temp_pool,
- "Invalid ExtFilterOptions option: ",
- arg,
- NULL);
- }
-
- return NULL;
-}
-
-static const char *parse_cmd(apr_pool_t *p, const char **args, ef_filter_t *filter)
-{
- if (**args == '"') {
- const char *start = *args + 1;
- char *parms;
-
- ++*args; /* move past leading " */
- while (**args && **args != '"') {
- ++*args;
- }
- if (**args != '"') {
- return "Expected cmd= delimiter";
- }
- parms = apr_pstrndup(p, start, *args - start);
- ++*args; /* move past trailing " */
-
- /* parms now has the command-line to parse */
- while (filter->numArgs < 30 &&
- strlen(filter->args[filter->numArgs] = ap_getword_white_nc(p, &parms))) {
- ++filter->numArgs;
- }
- if (filter->numArgs < 1) {
- return "cmd= parse error";
- }
- filter->args[filter->numArgs] = NULL; /* we stored "" in the while() loop */
- filter->command = filter->args[0];
- }
- else
- {
- /* simple path */
- filter->args[0] = ap_getword_white(p, args);
- if (!filter->args[0]) {
- return "Invalid cmd= parameter";
- }
- filter->numArgs = 1;
- filter->command = filter->args[0];
- }
- return NULL;
-}
-
-static const char *define_filter(cmd_parms *cmd, void *dummy, const char *args)
-{
- ef_server_t *conf = ap_get_module_config(cmd->server->module_config,
- &ext_filter_module);
- const char *token;
- const char *name;
- ef_filter_t *filter;
-
- name = ap_getword_white(cmd->pool, &args);
- if (!name) {
- return "Filter name not found";
- }
-
- if (apr_hash_get(conf->h, name, APR_HASH_KEY_STRING)) {
- return apr_psprintf(cmd->pool, "ExtFilter %s is already defined",
- name);
- }
-
- filter = (ef_filter_t *)apr_pcalloc(conf->p, sizeof(ef_filter_t));
- filter->name = name;
- filter->mode = OUTPUT_FILTER;
- apr_hash_set(conf->h, name, APR_HASH_KEY_STRING, filter);
-
- while (*args) {
- while (apr_isspace(*args)) {
- ++args;
- }
-
- /* Nasty parsing... I wish I could simply use ap_getword_white()
- * here and then look at the token, but ap_getword_white() doesn't
- * do the right thing when we have cmd="word word word"
- */
- if (!strncasecmp(args, "preservescontentlength", 22)) {
- token = ap_getword_white(cmd->pool, &args);
- if (!strcasecmp(token, "preservescontentlength")) {
- filter->preserves_content_length = 1;
- }
- else {
- return apr_psprintf(cmd->pool,
- "mangled argument `%s'",
- token);
- }
- continue;
- }
-
- if (!strncasecmp(args, "mode=", 5)) {
- args += 5;
- token = ap_getword_white(cmd->pool, &args);
- if (!strcasecmp(token, "output")) {
- filter->mode = OUTPUT_FILTER;
- }
- else if (!strcasecmp(token, "input")) {
- filter->mode = INPUT_FILTER;
- }
- else {
- return apr_psprintf(cmd->pool, "Invalid mode: `%s'",
- token);
- }
- continue;
- }
-
- if (!strncasecmp(args, "intype=", 7)) {
- args += 7;
- filter->intype = ap_getword_white(cmd->pool, &args);
- continue;
- }
-
- if (!strncasecmp(args, "outtype=", 8)) {
- args += 8;
- filter->outtype = ap_getword_white(cmd->pool, &args);
- continue;
- }
-
- if (!strncasecmp(args, "cmd=", 4)) {
- args += 4;
- if ((token = parse_cmd(cmd->pool, &args, filter))) {
- return token;
- }
- continue;
- }
-
- return apr_psprintf(cmd->pool, "Unexpected parameter: `%s'",
- args);
- }
-
- /* parsing is done... register the filter
- */
- if (filter->mode == OUTPUT_FILTER) {
- /* XXX need a way to ensure uniqueness among all filters */
- ap_register_output_filter(filter->name, ef_output_filter, AP_FTYPE_RESOURCE);
- }
-#if 0 /* no input filters yet */
- else if (filter->mode == INPUT_FILTER) {
- /* XXX need a way to ensure uniqueness among all filters */
- ap_register_input_filter(filter->name, ef_input_filter, AP_FTYPE_RESOURCE);
- }
-#endif
- else {
- ap_assert(1 != 1); /* we set the field wrong somehow */
- }
-
- return NULL;
-}
-
-static const command_rec cmds[] =
-{
- AP_INIT_ITERATE("ExtFilterOptions",
- add_options,
- NULL,
- ACCESS_CONF, /* same as SetInputFilter/SetOutputFilter */
- "valid options: DebugLevel=n, LogStderr, NoLogStderr"),
- AP_INIT_RAW_ARGS("ExtFilterDefine",
- define_filter,
- NULL,
- RSRC_CONF,
- "Define an external filter"),
- {NULL}
-};
-
-static apr_status_t set_resource_limits(request_rec *r,
- apr_procattr_t *procattr)
-{
-#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \
- defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
- core_dir_config *conf =
- (core_dir_config *)ap_get_module_config(r->per_dir_config,
- &core_module);
- apr_status_t rv;
-
-#ifdef RLIMIT_CPU
- rv = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu);
- ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
-#endif
-#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
- rv = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem);
- ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
-#endif
-#ifdef RLIMIT_NPROC
- rv = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc);
- ap_assert(rv == APR_SUCCESS); /* otherwise, we're out of sync with APR */
-#endif
-
-#endif /* if at least one limit defined */
-
- return APR_SUCCESS;
-}
-
-static apr_status_t ef_close_file(void *vfile)
-{
- return apr_file_close(vfile);
-}
-
-/* init_ext_filter_process: get the external filter process going
- * This is per-filter-instance (i.e., per-request) initialization.
- */
-static apr_status_t init_ext_filter_process(ap_filter_t *f)
-{
- ef_ctx_t *ctx = f->ctx;
- apr_status_t rc;
- ef_dir_t *dc = ctx->dc;
-
- ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc));
-
- rc = apr_procattr_create(&ctx->procattr, ctx->p);
- ap_assert(rc == APR_SUCCESS);
-
- rc = apr_procattr_io_set(ctx->procattr,
- APR_CHILD_BLOCK,
- APR_CHILD_BLOCK,
- APR_CHILD_BLOCK);
- ap_assert(rc == APR_SUCCESS);
-
- rc = set_resource_limits(f->r, ctx->procattr);
- ap_assert(rc == APR_SUCCESS);
-
- if (dc->log_stderr > 0) {
- rc = apr_procattr_child_err_set(ctx->procattr,
- f->r->server->error_log, /* stderr in child */
- NULL);
- ap_assert(rc == APR_SUCCESS);
- }
-
- rc = apr_proc_create(ctx->proc,
- ctx->filter->command,
- (const char * const *)ctx->filter->args,
- NULL, /* environment */
- ctx->procattr,
- ctx->p);
- if (rc != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r,
- "couldn't create child process to run `%s'",
- ctx->filter->command);
- return rc;
- }
-
- apr_pool_note_subprocess(ctx->p, ctx->proc, APR_KILL_AFTER_TIMEOUT);
-
- /* We don't want the handle to the child's stdin inherited by any
- * other processes created by httpd. Otherwise, when we close our
- * handle, the child won't see EOF because another handle will still
- * be open.
- */
-
- apr_pool_cleanup_register(ctx->p, ctx->proc->in,
- apr_pool_cleanup_null, /* other mechanism */
- ef_close_file);
-
-#if APR_FILES_AS_SOCKETS
- {
- apr_socket_t *newsock;
-
- rc = apr_poll_setup(&ctx->pollset, 2, ctx->p);
- ap_assert(rc == APR_SUCCESS);
- rc = apr_socket_from_file(&newsock, ctx->proc->in);
- ap_assert(rc == APR_SUCCESS);
- rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLOUT);
- ap_assert(rc == APR_SUCCESS);
- rc = apr_socket_from_file(&newsock, ctx->proc->out);
- ap_assert(rc == APR_SUCCESS);
- rc = apr_poll_socket_add(ctx->pollset, newsock, APR_POLLIN);
- ap_assert(rc == APR_SUCCESS);
- }
-#endif
-
- return APR_SUCCESS;
-}
-
-static const char *get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t *p)
-{
- const char *debug_str = dc->debug == -1 ?
- "DebugLevel=0" : apr_psprintf(p, "DebugLevel=%d", dc->debug);
- const char *log_stderr_str = dc->log_stderr < 1 ?
- "NoLogStderr" : "LogStderr";
- const char *preserve_content_length_str = filter->preserves_content_length ?
- "PreservesContentLength" : "!PreserveContentLength";
- const char *intype_str = !filter->intype ?
- "*/*" : filter->intype;
- const char *outtype_str = !filter->outtype ?
- "(unchanged)" : filter->outtype;
-
- return apr_psprintf(p,
- "ExtFilterOptions %s %s %s ExtFilterInType %s "
- "ExtFilterOuttype %s",
- debug_str, log_stderr_str, preserve_content_length_str,
- intype_str, outtype_str);
-}
-
-static apr_status_t init_filter_instance(ap_filter_t *f)
-{
- ef_ctx_t *ctx;
- ef_dir_t *dc;
- ef_server_t *sc;
- apr_status_t rv;
-
- f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(ef_ctx_t));
- dc = ap_get_module_config(f->r->per_dir_config,
- &ext_filter_module);
- sc = ap_get_module_config(f->r->server->module_config,
- &ext_filter_module);
- ctx->dc = dc;
- /* look for the user-defined filter */
- ctx->filter = apr_hash_get(sc->h, f->frec->name, APR_HASH_KEY_STRING);
- if (!ctx->filter) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r,
- "couldn't find definition of filter '%s'",
- f->frec->name);
- return APR_EINVAL;
- }
- ctx->p = f->r->pool;
- if (ctx->filter->intype &&
- ctx->filter->intype != INTYPE_ALL &&
- strcasecmp(ctx->filter->intype, f->r->content_type)) {
- /* wrong IMT for us; don't mess with the output */
- ctx->noop = 1;
- }
- else {
- rv = init_ext_filter_process(f);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- if (ctx->filter->outtype &&
- ctx->filter->outtype != OUTTYPE_UNCHANGED) {
- f->r->content_type = ctx->filter->outtype;
- }
- if (ctx->filter->preserves_content_length != 1) {
- /* nasty, but needed to avoid confusing the browser
- */
- apr_table_unset(f->r->headers_out, "Content-Length");
- }
- }
-
- if (dc->debug >= DBGLVL_SHOWOPTIONS) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r,
- "%sfiltering `%s' through `%s', cfg %s",
- ctx->noop ? "skipping: " : "",
- f->r->uri ? f->r->uri : f->r->filename,
- ctx->filter->command,
- get_cfg_string(dc, ctx->filter, f->r->pool));
- }
-
- return APR_SUCCESS;
-}
-
-/* drain_available_output():
- *
- * if any data is available from the filter, read it and pass it
- * to the next filter
- */
-static apr_status_t drain_available_output(ap_filter_t *f)
-{
- ef_ctx_t *ctx = f->ctx;
- ef_dir_t *dc = ctx->dc;
- apr_size_t len;
- char buf[4096];
- apr_status_t rv;
- apr_bucket_brigade *bb;
- apr_bucket *b;
-
- while (1) {
- len = sizeof(buf);
- rv = apr_file_read(ctx->proc->out,
- buf,
- &len);
- if ((rv && !APR_STATUS_IS_EAGAIN(rv)) ||
- dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r,
- "apr_file_read(child output), len %" APR_SIZE_T_FMT,
- !rv ? len : -1);
- }
- if (rv != APR_SUCCESS) {
- return rv;
- }
- bb = apr_brigade_create(f->r->pool);
- b = apr_bucket_transient_create(buf, len);
- APR_BRIGADE_INSERT_TAIL(bb, b);
- if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "ap_pass_brigade()");
- return rv;
- }
- }
- /* we should never get here; if we do, a bogus error message would be
- * the least of our problems
- */
- return APR_ANONYMOUS;
-}
-
-static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data,
- apr_ssize_t len)
-{
- ef_ctx_t *ctx = f->ctx;
- ef_dir_t *dc = ctx->dc;
- apr_status_t rv;
- apr_size_t bytes_written = 0;
- apr_size_t tmplen;
-
- do {
- tmplen = len - bytes_written;
- rv = apr_file_write(ctx->proc->in,
- (const char *)data + bytes_written,
- &tmplen);
- bytes_written += tmplen;
- if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "apr_file_write(child input), len %" APR_SIZE_T_FMT,
- tmplen);
- return rv;
- }
- if (APR_STATUS_IS_EAGAIN(rv)) {
- /* XXX handle blocking conditions here... if we block, we need
- * to read data from the child process and pass it down to the
- * next filter!
- */
- rv = drain_available_output(f);
- if (APR_STATUS_IS_EAGAIN(rv)) {
-#if APR_FILES_AS_SOCKETS
- int num_events;
-
- rv = apr_poll(ctx->pollset,
- &num_events,
- f->r->server->timeout * APR_USEC_PER_SEC);
- if (rv || dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG,
- rv, f->r, "apr_poll()");
- }
- if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) {
- /* some error such as APR_TIMEUP */
- return rv;
- }
-#else /* APR_FILES_AS_SOCKETS */
- /* Yuck... I'd really like to wait until I can read
- * or write, but instead I have to sleep and try again
- */
- apr_sleep(100000); /* 100 milliseconds */
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO,
- 0, f->r, "apr_sleep()");
- }
-#endif /* APR_FILES_AS_SOCKETS */
- }
- else if (rv != APR_SUCCESS) {
- return rv;
- }
- }
- } while (bytes_written < len);
- return rv;
-}
-
-static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- ef_ctx_t *ctx = f->ctx;
- apr_bucket *b;
- ef_dir_t *dc;
- apr_size_t len;
- const char *data;
- apr_status_t rv;
- char buf[4096];
- apr_bucket *eos = NULL;
-
- if (!ctx) {
- if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
- return rv;
- }
- ctx = f->ctx;
- }
- if (ctx->noop) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
- dc = ctx->dc;
-
- APR_BRIGADE_FOREACH(b, bb) {
-
- if (APR_BUCKET_IS_EOS(b)) {
- eos = b;
- break;
- }
-
- rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read()");
- return rv;
- }
-
- if (len > 0 &&
- (rv = pass_data_to_filter(f, data, len)) != APR_SUCCESS) {
- return rv;
- }
- }
-
- apr_brigade_destroy(bb);
-
- /* XXX What we *really* need to do once we've hit eos is create a pipe bucket
- * from the child output pipe and pass down the pipe bucket + eos.
- */
- if (eos) {
- /* close the child's stdin to signal that no more data is coming;
- * that will cause the child to finish generating output
- */
- if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "apr_file_close(child input)");
- return rv;
- }
- /* since we've seen eos and closed the child's stdin, set the proper pipe
- * timeout; we don't care if we don't return from apr_file_read() for a while...
- */
- rv = apr_file_pipe_timeout_set(ctx->proc->out,
- f->r->server->timeout * APR_USEC_PER_SEC);
- if (rv) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "apr_file_pipe_timeout_set(child output)");
- return rv;
- }
- }
-
- do {
- len = sizeof(buf);
- rv = apr_file_read(ctx->proc->out,
- buf,
- &len);
- if ((rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv)) ||
- dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r,
- "apr_file_read(child output), len %" APR_SIZE_T_FMT,
- !rv ? len : -1);
- }
- if (APR_STATUS_IS_EAGAIN(rv)) {
- if (eos) {
- /* should not occur, because we have an APR timeout in place */
- AP_DEBUG_ASSERT(1 != 1);
- }
- return APR_SUCCESS;
- }
-
- if (rv == APR_SUCCESS) {
- bb = apr_brigade_create(f->r->pool);
- b = apr_bucket_transient_create(buf, len);
- APR_BRIGADE_INSERT_TAIL(bb, b);
- if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "ap_pass_brigade(filtered buffer) failed");
- return rv;
- }
- }
- } while (rv == APR_SUCCESS);
-
- if (!APR_STATUS_IS_EOF(rv)) {
- return rv;
- }
-
- if (eos) {
- /* pass down eos */
- bb = apr_brigade_create(f->r->pool);
- b = apr_bucket_eos_create();
- APR_BRIGADE_INSERT_TAIL(bb, b);
- if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "ap_pass_brigade(eos) failed");
- return rv;
- }
- }
-
- return APR_SUCCESS;
-}
-
-#if 0
-static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
- ap_input_mode_t mode, apr_read_type_e block,
- apr_off_t readbytes)
-{
- apr_status_t rv;
- apr_bucket *b;
- char *buf;
- apr_ssize_t len;
- char *zero;
-
- rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
- if (rv != APR_SUCCESS) {
- return rv;
- }
-
- APR_BRIGADE_FOREACH(b, bb) {
- if (!APR_BUCKET_IS_EOS(b)) {
- if ((rv = apr_bucket_read(b, (const char **)&buf, &len, APR_BLOCK_READ)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "apr_bucket_read() failed");
- return rv;
- }
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "apr_bucket_read -> %d bytes",
- len);
- while ((zero = memchr(buf, '0', len))) {
- *zero = 'a';
- }
- }
- else
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "got eos bucket");
- }
-
- return rv;
-}
-#endif
-
-module AP_MODULE_DECLARE_DATA ext_filter_module =
-{
- STANDARD20_MODULE_STUFF,
- create_ef_dir_conf,
- merge_ef_dir_conf,
- create_ef_server_conf,
- NULL,
- cmds,
-};
diff --git a/modules/experimental/mod_ext_filter.exp b/modules/experimental/mod_ext_filter.exp
deleted file mode 100644
index ed3b8fc60c..0000000000
--- a/modules/experimental/mod_ext_filter.exp
+++ /dev/null
@@ -1 +0,0 @@
-ext_filter_module
diff --git a/modules/experimental/mod_mem_cache.c b/modules/experimental/mod_mem_cache.c
deleted file mode 100644
index 00eb45e7dd..0000000000
--- a/modules/experimental/mod_mem_cache.c
+++ /dev/null
@@ -1,890 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
- */
-
-#define CORE_PRIVATE
-/* CACHE_FD will eventually be exposed as a configuration directive */
-#define CACHE_FD 0
-#include "mod_cache.h"
-#include "ap_mpm.h"
-#include "apr_thread_mutex.h"
-
-/* USE_ATOMICS should be replaced with the appropriate APR feature macro */
-#define USE_ATOMICS
-#ifdef USE_ATOMICS
-#include "apr_atomic.h"
-#endif
-
-#if !APR_HAS_THREADS
-#error This module does not currently compile unless you have a thread-capable APR. Sorry!
-#endif
-
-module AP_MODULE_DECLARE_DATA mem_cache_module;
-
-/*
- * XXX
- * This cache uses apr_hash functions which leak storage when something is removed
- * from the cache. This can be fixed in the apr_hash functions by making them use
- * malloc/free rather than pools to manage their storage requirements.
- */
-
-typedef enum {
- CACHE_TYPE_FILE = 1,
- CACHE_TYPE_HEAP,
- CACHE_TYPE_MMAP
-} cache_type_e;
-
-typedef struct {
- char* hdr;
- char* val;
-} cache_header_tbl_t;
-
-typedef struct mem_cache_object {
- cache_type_e type;
- apr_ssize_t num_header_out;
- apr_ssize_t num_subprocess_env;
- apr_ssize_t num_notes;
- cache_header_tbl_t *header_out;
- cache_header_tbl_t *subprocess_env;
- cache_header_tbl_t *notes;
- apr_size_t m_len;
- void *m;
- apr_os_file_t fd;
-} mem_cache_object_t;
-
-typedef struct {
- apr_thread_mutex_t *lock;
- apr_hash_t *cacheht;
- apr_size_t cache_size;
- apr_size_t object_cnt;
-
- /* Fields set by config directives */
- apr_size_t min_cache_object_size;
- apr_size_t max_cache_object_size;
- apr_size_t max_cache_size;
- apr_size_t max_object_cnt;
-
-} mem_cache_conf;
-static mem_cache_conf *sconf;
-
-#define DEFAULT_MAX_CACHE_SIZE 100*1024
-#define DEFAULT_MIN_CACHE_OBJECT_SIZE 0
-#define DEFAULT_MAX_CACHE_OBJECT_SIZE 10000
-#define DEFAULT_MAX_OBJECT_CNT 1000
-#define CACHEFILE_LEN 20
-
-/* Forward declarations */
-static int remove_entity(cache_handle_t *h);
-static apr_status_t write_headers(cache_handle_t *h, request_rec *r, cache_info *i);
-static apr_status_t write_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);
-static apr_status_t read_headers(cache_handle_t *h, request_rec *r);
-static apr_status_t read_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
-
-static void cleanup_cache_object(cache_object_t *obj)
-{
- mem_cache_object_t *mobj = obj->vobj;
-
- /* TODO:
- * We desperately need a more efficient way of allocating objects. We're
- * making way too many malloc calls to create a fully populated
- * cache object...
- */
-
- /* Cleanup the cache_object_t */
- if (obj->key) {
- free(obj->key);
- }
- if (obj->info.content_type) {
- free(obj->info.content_type);
- }
- if (obj->info.etag) {
- free(obj->info.etag);
- }
- if (obj->info.lastmods) {
- free(obj->info.lastmods);
- }
- if (obj->info.filename) {
- free(obj->info.filename);
- }
-
- free(obj);
-
- /* Cleanup the mem_cache_object_t */
- if (mobj) {
- if (mobj->type == CACHE_TYPE_HEAP && mobj->m) {
- free(mobj->m);
- }
- if (mobj->type == CACHE_TYPE_FILE && mobj->fd) {
-#ifdef WIN32
- CloseHandle(mobj->fd);
-#else
- close(mobj->fd);
-#endif
- }
- if (mobj->header_out) {
- if (mobj->header_out[0].hdr)
- free(mobj->header_out[0].hdr);
- free(mobj->header_out);
- }
- if (mobj->subprocess_env) {
- if (mobj->subprocess_env[0].hdr)
- free(mobj->subprocess_env[0].hdr);
- free(mobj->subprocess_env);
- }
- if (mobj->notes) {
- if (mobj->notes[0].hdr)
- free(mobj->notes[0].hdr);
- free(mobj->notes);
- }
- free(mobj);
- }
- return;
-}
-static apr_status_t decrement_refcount(void *arg)
-{
- cache_object_t *obj = (cache_object_t *) arg;
-
- /* If obj->complete is not set, the cache update failed and the
- * object needs to be removed from the cache.
- */
- if (!obj->complete) {
- mem_cache_object_t *mobj = (mem_cache_object_t *) obj->vobj;
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), NULL);
- sconf->object_cnt--;
- sconf->cache_size -= mobj->m_len;
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
- }
-
- /* Cleanup the cache object */
-#ifdef USE_ATOMICS
- if (!apr_atomic_dec(&obj->refcount)) {
- if (obj->cleanup) {
- cleanup_cache_object(obj);
- }
- }
-#else
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- obj->refcount--;
- /* If the object is marked for cleanup and the refcount
- * has dropped to zero, cleanup the object
- */
- if ((obj->cleanup) && (!obj->refcount)) {
- cleanup_cache_object(obj);
- }
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
-#endif
- return APR_SUCCESS;
-}
-static apr_status_t cleanup_cache_mem(void *sconfv)
-{
- cache_object_t *obj;
- apr_hash_index_t *hi;
- mem_cache_conf *co = (mem_cache_conf*) sconfv;
-
- if (!co) {
- return APR_SUCCESS;
- }
-
- /* Iterate over the cache and clean up each entry */
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- for (hi = apr_hash_first(NULL, co->cacheht); hi; hi=apr_hash_next(hi)) {
- apr_hash_this(hi, NULL, NULL, (void **)&obj);
- if (obj) {
-#ifdef USE_ATOMICS
- apr_atomic_inc(&obj->refcount);
- obj->cleanup = 1;
- if (!apr_atomic_dec(&obj->refcount)) {
-#else
- obj->cleanup = 1;
- if (!obj->refcount) {
-#endif
- cleanup_cache_object(obj);
- }
- }
- }
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
- return APR_SUCCESS;
-}
-/*
- * TODO: enable directives to be overridden in various containers
- */
-static void *create_cache_config(apr_pool_t *p, server_rec *s)
-{
- int threaded_mpm;
-
- sconf = apr_pcalloc(p, sizeof(mem_cache_conf));
-
-
- ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm);
- if (threaded_mpm) {
- apr_thread_mutex_create(&sconf->lock, APR_THREAD_MUTEX_DEFAULT, p);
- }
- sconf->cacheht = apr_hash_make(p);
-
- sconf->min_cache_object_size = DEFAULT_MIN_CACHE_OBJECT_SIZE;
- sconf->max_cache_object_size = DEFAULT_MAX_CACHE_OBJECT_SIZE;
- /* Number of objects in the cache */
- sconf->max_object_cnt = DEFAULT_MAX_OBJECT_CNT;
- sconf->object_cnt = 0;
- /* Size of the cache in KB */
- sconf->max_cache_size = DEFAULT_MAX_CACHE_SIZE;
- sconf->cache_size = 0;
-
- apr_pool_cleanup_register(p, NULL, cleanup_cache_mem, apr_pool_cleanup_null);
-
- return sconf;
-}
-
-static int create_entity(cache_handle_t *h, request_rec *r,
- const char *type,
- const char *key,
- apr_size_t len)
-{
- cache_object_t *obj, *tmp_obj;
- mem_cache_object_t *mobj;
-
- if (strcasecmp(type, "mem")) {
- return DECLINED;
- }
-
- if (len < sconf->min_cache_object_size ||
- len > sconf->max_cache_object_size) {
- return DECLINED;
- }
-
- /*
- * TODO: Get smarter about managing the cache size.
- * If the cache is full, we need to do garbage collection
- * to weed out old/stale entries
- */
- if ((sconf->cache_size + len) > sconf->max_cache_size) {
- return DECLINED;
- }
-
- if (sconf->object_cnt >= sconf->max_object_cnt) {
- return DECLINED;
- }
-
- /* Allocate and initialize cache_object_t */
- obj = calloc(1, sizeof(*obj));
- if (!obj) {
- return DECLINED;
- }
- obj->key = calloc(1, strlen(key) + 1);
- if (!obj->key) {
- cleanup_cache_object(obj);
- return DECLINED;
- }
- strncpy(obj->key, key, strlen(key) + 1);
- obj->info.len = len;
-
-
- /* Allocate and init mem_cache_object_t */
- mobj = calloc(1, sizeof(*mobj));
- if (!mobj) {
- cleanup_cache_object(obj);
- return DECLINED;
- }
-
- /* Reference mem_cache_object_t out of cache_object_t */
- obj->vobj = mobj;
- mobj->m_len = len;
- obj->complete = 0;
- obj->refcount = 1;
-
- /* Place the cache_object_t into the hash table.
- * Note: Perhaps we should wait to put the object in the
- * hash table when the object is complete? I add the object here to
- * avoid multiple threads attempting to cache the same content only
- * to discover at the very end that only one of them will suceed.
- * Furthermore, adding the cache object to the table at the end could
- * open up a subtle but easy to exploit DoS hole: someone could request
- * a very large file with multiple requests. Better to detect this here
- * rather than after the cache object has been completely built and
- * initialized...
- * XXX Need a way to insert into the cache w/o such coarse grained locking
- */
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- tmp_obj = (cache_object_t *) apr_hash_get(sconf->cacheht,
- key,
- APR_HASH_KEY_STRING);
- if (!tmp_obj) {
- apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), obj);
- sconf->object_cnt++;
- sconf->cache_size += len;
- }
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
-
- if (tmp_obj) {
- /* This thread collided with another thread loading the same object
- * into the cache at the same time. Defer to the other thread which
- * is further along.
- */
- cleanup_cache_object(obj);
- return DECLINED;
- }
-
- /* Set the cleanup flag and register the cleanup to cleanup
- * the cache_object_t if the cache load is aborted.
- */
- obj->cleanup = 1;
- apr_pool_cleanup_register(r->pool, obj, decrement_refcount,
- apr_pool_cleanup_null);
-
- /* Populate the cache handle */
- h->cache_obj = obj;
- h->read_body = &read_body;
- h->read_headers = &read_headers;
- h->write_body = &write_body;
- h->write_headers = &write_headers;
- h->remove_entity = &remove_entity;
-
- return OK;
-}
-
-static int open_entity(cache_handle_t *h, request_rec *r, const char *type, const char *key)
-{
- cache_object_t *obj;
-
- /* Look up entity keyed to 'url' */
- if (strcasecmp(type, "mem")) {
- return DECLINED;
- }
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key,
- APR_HASH_KEY_STRING);
- if (obj) {
- if (obj->complete) {
- obj->refcount++;
- apr_pool_cleanup_register(r->pool, obj, decrement_refcount,
- apr_pool_cleanup_null);
- }
- else {
- obj = NULL;
- }
- }
-
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
-
- if (!obj) {
- return DECLINED;
- }
-
- /* Initialize the cache_handle */
- h->read_body = &read_body;
- h->read_headers = &read_headers;
- h->write_body = &write_body;
- h->write_headers = &write_headers;
- h->remove_entity = &remove_entity;
- h->cache_obj = obj;
-
- return OK;
-}
-
-static int remove_entity(cache_handle_t *h)
-{
- cache_object_t *obj = h->cache_obj;
-
- /* Remove the cache object from the cache */
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- obj = (cache_object_t *) apr_hash_get(sconf->cacheht, obj->key,
- APR_HASH_KEY_STRING);
- if (obj) {
- mem_cache_object_t *mobj = (mem_cache_object_t *) obj->vobj;
- apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), NULL);
- sconf->object_cnt--;
- sconf->cache_size -= mobj->m_len;
- }
- else {
- /* If the object was removed from the cache prior to this function being
- * called, then obj == NULL. Reinit obj with the object being cleaned up.
- * Note: This code assumes that there is at most only one object in the
- * cache per key.
- */
- obj = h->cache_obj;
- }
-
- /* Cleanup the cache object
- * Set obj->cleanup to ensure decrement_refcount cleans up the obj if it
- * is still being referenced by another thread
- */
- obj->cleanup = 1;
-#ifndef USE_ATOMICS
- obj->refcount--;
- if (!obj->refcount) {
- cleanup_cache_object(obj);
- }
-#endif
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
-#ifdef USE_ATOMICS
- if (!apr_atomic_dec(&obj->refcount)) {
- cleanup_cache_object(obj);
- }
-#endif
- h->cache_obj = NULL;
- return OK;
-}
-static apr_status_t serialize_table(cache_header_tbl_t **obj,
- apr_ssize_t *nelts,
- apr_table_t *table)
-{
- apr_table_entry_t *elts = (apr_table_entry_t *) table->a.elts;
- apr_ssize_t i;
- apr_size_t len = 0;
- apr_size_t idx = 0;
- char *buf;
-
- *nelts = table->a.nelts;
- if (*nelts == 0 ) {
- *obj=NULL;
- return APR_SUCCESS;
- }
- *obj = calloc(1, sizeof(cache_header_tbl_t) * table->a.nelts);
- if (NULL == *obj) {
- return APR_ENOMEM;
- }
- for (i = 0; i < table->a.nelts; ++i) {
- len += strlen(elts[i].key);
- len += strlen(elts[i].val);
- len += 2; /* Extra space for NULL string terminator for key and val */
- }
-
- /* Transfer the headers into a contiguous memory block */
- buf = calloc(1, len);
- if (!buf) {
- *obj = NULL;
- return APR_ENOMEM;
- }
-
- for (i = 0; i < *nelts; ++i) {
- (*obj)[i].hdr = &buf[idx];
- len = strlen(elts[i].key) + 1; /* Include NULL terminator */
- strncpy(&buf[idx], elts[i].key, len);
- idx+=len;
-
- (*obj)[i].val = &buf[idx];
- len = strlen(elts[i].val) + 1;
- strncpy(&buf[idx], elts[i].val, len);
- idx+=len;
- }
- return APR_SUCCESS;
-}
-static int unserialize_table( cache_header_tbl_t *ctbl,
- int num_headers,
- apr_table_t *t )
-{
- int i;
-
- for (i = 0; i < num_headers; ++i) {
- apr_table_setn(t, ctbl[i].hdr, ctbl[i].val);
- }
-
- return APR_SUCCESS;
-}
-/* Define request processing hook handlers */
-static int remove_url(const char *type, const char *key)
-{
- cache_object_t *obj;
-
- if (strcasecmp(type, "mem")) {
- return DECLINED;
- }
-
- /* WIBNIF
- * apr_hash_set(..,..,..,NULL) returned pointer to the object just removed.
- * That way, we could free the object w/o doing another call to an
- * apr_hash function.
- */
-
- /* First, find the object in the cache */
- if (sconf->lock) {
- apr_thread_mutex_lock(sconf->lock);
- }
- obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key,
- APR_HASH_KEY_STRING);
- if (obj) {
- mem_cache_object_t *mobj = (mem_cache_object_t *) obj->vobj;
- apr_hash_set(sconf->cacheht, key, APR_HASH_KEY_STRING, NULL);
- sconf->object_cnt--;
- sconf->cache_size -= mobj->m_len;
- /* Set cleanup to ensure decrement_refcount cleans up the obj if it
- * is still being referenced by another thread
- */
- obj->cleanup = 1;
-#ifdef USE_ATOMICS
- /* Refcount increment MUST be made under protection of the lock */
- obj->refcount++;
-#else
- if (!obj->refcount) {
- cleanup_cache_object(obj);
- }
-#endif
- }
- if (sconf->lock) {
- apr_thread_mutex_unlock(sconf->lock);
- }
-#ifdef USE_ATOMICS
- if (obj) {
- if (!apr_atomic_dec(&obj->refcount)) {
- cleanup_cache_object(obj);
- }
- }
-#endif
- return OK;
-}
-
-static apr_status_t read_headers(cache_handle_t *h, request_rec *r)
-{
- int rc;
- mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
-
- r->headers_out = apr_table_make(r->pool,mobj->num_header_out);
- r->subprocess_env = apr_table_make(r->pool, mobj->num_subprocess_env);
- r->notes = apr_table_make(r->pool, mobj->num_notes);
- rc = unserialize_table( mobj->header_out,
- mobj->num_header_out,
- r->headers_out);
- rc = unserialize_table( mobj->subprocess_env,
- mobj->num_subprocess_env,
- r->subprocess_env);
- rc = unserialize_table( mobj->notes,
- mobj->num_notes,
- r->notes);
- return rc;
-}
-
-static apr_status_t read_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb)
-{
- apr_bucket *b;
- mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
-
- if (mobj->type == CACHE_TYPE_FILE) {
- /* CACHE_TYPE_FILE */
- apr_file_t *file;
- apr_os_file_put(&file, &mobj->fd, APR_READ|APR_XTHREAD, p);
- b = apr_bucket_file_create(file, 0, mobj->m_len, p);
- }
- else {
- /* CACHE_TYPE_HEAP */
- b = apr_bucket_immortal_create(mobj->m, mobj->m_len);
- }
- APR_BRIGADE_INSERT_TAIL(bb, b);
- b = apr_bucket_eos_create();
- APR_BRIGADE_INSERT_TAIL(bb, b);
-
- return APR_SUCCESS;
-}
-
-
-static apr_status_t write_headers(cache_handle_t *h, request_rec *r, cache_info *info)
-{
- cache_object_t *obj = h->cache_obj;
- mem_cache_object_t *mobj = (mem_cache_object_t*) obj->vobj;
- int rc;
-
- /* Precompute how much storage we need to hold the headers */
- rc = serialize_table(&mobj->header_out,
- &mobj->num_header_out,
- r->headers_out);
- if (rc != APR_SUCCESS) {
- return rc;
- }
- rc = serialize_table(&mobj->subprocess_env,
- &mobj->num_subprocess_env,
- r->subprocess_env );
- if (rc != APR_SUCCESS) {
- return rc;
- }
-
- rc = serialize_table(&mobj->notes, &mobj->num_notes, r->notes);
- if (rc != APR_SUCCESS) {
- return rc;
- }
-
- /* Init the info struct */
- if (info->date) {
- obj->info.date = info->date;
- }
- if (info->lastmod) {
- obj->info.lastmod = info->lastmod;
- }
- if (info->expire) {
- obj->info.expire = info->expire;
- }
- if (info->content_type) {
- obj->info.content_type = (char*) calloc(1, strlen(info->content_type) + 1);
- if (!obj->info.content_type) {
- return APR_ENOMEM;
- }
- strcpy(obj->info.content_type, info->content_type);
- }
- if ( info->filename) {
- obj->info.filename = (char*) calloc(1, strlen(info->filename) + 1);
- if (!obj->info.filename ) {
- return APR_ENOMEM;
- }
- strcpy(obj->info.filename, info->filename );
- }
-
- return APR_SUCCESS;
-}
-
-static apr_status_t write_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b)
-{
- apr_status_t rv;
- cache_object_t *obj = h->cache_obj;
- mem_cache_object_t *mobj = (mem_cache_object_t*) obj->vobj;
- apr_read_type_e eblock = APR_BLOCK_READ;
- apr_bucket *e;
- char *cur;
-
- if (CACHE_FD) {
- apr_file_t *file = NULL;
- int fd = 0;
- int other = 0;
-
- /* We can cache an open file descriptor if:
- * - the brigade contains one and only one file_bucket &&
- * - the brigade is complete &&
- * - the file_bucket is the last data bucket in the brigade
- */
- APR_BRIGADE_FOREACH(e, b) {
- if (APR_BUCKET_IS_EOS(e)) {
- obj->complete = 1;
- }
- else if (APR_BUCKET_IS_FILE(e)) {
- apr_bucket_file *a = e->data;
- fd++;
- file = a->fd;
- }
- else {
- other++;
- }
- }
- if (fd == 1 && !other && obj->complete) {
- apr_file_t *tmpfile;
-
- mobj->type = CACHE_TYPE_FILE;
- /* Open a new XTHREAD handle to the file */
- rv = apr_file_open(&tmpfile, r->filename,
- APR_READ | APR_BINARY | APR_XTHREAD | APR_FILE_NOCLEANUP,
- APR_OS_DEFAULT, r->pool);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- apr_file_unset_inherit(tmpfile);
- apr_os_file_get(&(mobj->fd), tmpfile);
-
- obj->cleanup = 0;
- obj->refcount--; /* Count should be 0 now */
- apr_pool_cleanup_kill(r->pool, obj, decrement_refcount);
-
- /* Open for business */
- obj->complete = 1;
- return APR_SUCCESS;
- }
- }
-
- /*
- * FD cacheing is not enabled or the content was not
- * suitable for fd caching.
- */
- if (mobj->m == NULL) {
- mobj->m = malloc(mobj->m_len);
- if (mobj->m == NULL) {
- return APR_ENOMEM;
- }
- mobj->type = CACHE_TYPE_HEAP;
- obj->count = 0;
- }
- cur = (char*) mobj->m + obj->count;
-
- /* Iterate accross the brigade and populate the cache storage */
- APR_BRIGADE_FOREACH(e, b) {
- const char *s;
- apr_size_t len;
-
- if (APR_BUCKET_IS_EOS(e)) {
- obj->cleanup = 0;
- obj->refcount--; /* Count should be 0 now */
- apr_pool_cleanup_kill(r->pool, obj, decrement_refcount);
-
- /* Open for business */
- obj->complete = 1;
- break;
- }
- rv = apr_bucket_read(e, &s, &len, eblock);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- /* XXX Check for overflow */
- if (len ) {
- memcpy(cur, s, len);
- cur+=len;
- obj->count+=len;
- }
- /* This should not happen, but if it does, we are in BIG trouble
- * cause we just stomped all over the heap.
- */
- AP_DEBUG_ASSERT(obj->count > mobj->m_len);
- }
- return APR_SUCCESS;
-}
-
-static const char
-*set_max_cache_size(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- int val;
-
- if (sscanf(arg, "%d", &val) != 1) {
- return "CacheSize value must be an integer (kBytes)";
- }
- sconf->max_cache_size = val;
- return NULL;
-}
-static const char
-*set_min_cache_object_size(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- apr_size_t val;
-
- if (sscanf(arg, "%d", &val) != 1) {
- return "CacheMinObjectSize value must be an integer (bytes)";
- }
- sconf->min_cache_object_size = val;
- return NULL;
-}
-static const char
-*set_max_cache_object_size(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- apr_size_t val;
-
- if (sscanf(arg, "%d", &val) != 1) {
- return "CacheMaxObjectSize value must be an integer (KB)";
- }
- sconf->max_cache_object_size = val;
- return NULL;
-}
-static const char
-*set_max_object_count(cmd_parms *parms, void *in_struct_ptr, const char *arg)
-{
- apr_size_t val;
-
- if (sscanf(arg, "%d", &val) != 1) {
- return "CacheMaxObjectCount value must be an integer";
- }
- sconf->max_object_cnt = val;
- return NULL;
-}
-
-static const command_rec cache_cmds[] =
-{
- AP_INIT_TAKE1("CacheSize", set_max_cache_size, NULL, RSRC_CONF,
- "The maximum space used by the cache in KB"),
- AP_INIT_TAKE1("CacheMaxObjectCount", set_max_object_count, NULL, RSRC_CONF,
- "The maximum number of objects allowed to be placed in the cache"),
- AP_INIT_TAKE1("CacheMinObjectSize", set_min_cache_object_size, NULL, RSRC_CONF,
- "The minimum size (in bytes) of an object to be placed in the cache"),
- AP_INIT_TAKE1("CacheMaxObjectSize", set_max_cache_object_size, NULL, RSRC_CONF,
- "The maximum size (in KB) of an object to be placed in the cache"),
- {NULL}
-};
-
-static void register_hooks(apr_pool_t *p)
-{
- /* cache initializer */
-/* cache_hook_cache_init(cache_init, NULL, NULL, AP_HOOK_FIRST); */
- cache_hook_create_entity(create_entity, NULL, NULL, APR_HOOK_MIDDLE);
- cache_hook_open_entity(open_entity, NULL, NULL, APR_HOOK_MIDDLE);
- cache_hook_remove_url(remove_url, NULL, NULL, APR_HOOK_MIDDLE);
-}
-
-module AP_MODULE_DECLARE_DATA mem_cache_module =
-{
- STANDARD20_MODULE_STUFF,
- NULL, /* create per-directory config structure */
- NULL, /* merge per-directory config structures */
- create_cache_config, /* create per-server config structure */
- NULL, /* merge per-server config structures */
- cache_cmds, /* command apr_table_t */
- register_hooks
-};
-
diff --git a/modules/experimental/mod_mem_cache.dsp b/modules/experimental/mod_mem_cache.dsp
deleted file mode 100644
index ca8999bf04..0000000000
--- a/modules/experimental/mod_mem_cache.dsp
+++ /dev/null
@@ -1,111 +0,0 @@
-# Microsoft Developer Studio Project File - Name="mod_mem_cache" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=mod_mem_cache - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "mod_mem_cache.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "mod_mem_cache.mak" CFG="mod_mem_cache - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_mem_cache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_mem_cache - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "mod_mem_cache - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "mod_mem_cache_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../../os/win32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/mod_mem_cache.so"
-
-!ELSEIF "$(CFG)" == "mod_mem_cache - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "mod_mem_cache_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../../os/win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/mod_mem_cache.so" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "mod_mem_cache - Win32 Release"
-# Name "mod_mem_cache - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\mod_mem_cache.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\mod_cache.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/modules/experimental/util_ldap.c b/modules/experimental/util_ldap.c
deleted file mode 100644
index 5ff3dd1eae..0000000000
--- a/modules/experimental/util_ldap.c
+++ /dev/null
@@ -1,1104 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2001 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- */
-
-/*
- * util_ldap.c: LDAP things
- *
- * Original code from auth_ldap module for Apache v1.3:
- * Copyright 1998, 1999 Enbridge Pipelines Inc.
- * Copyright 1999-2001 Dave Carrigan
- */
-
-#include <apr_ldap.h>
-
-#ifdef APU_HAS_LDAP
-
-#include <apr_strings.h>
-
-#include "ap_config.h"
-#include "httpd.h"
-#include "http_config.h"
-#include "http_core.h"
-#include "http_log.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "util_ldap.h"
-#include "util_ldap_cache.h"
-
-#if APR_HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-module AP_MODULE_DECLARE_DATA ldap_module;
-
-int util_ldap_handler(request_rec *r);
-void *util_ldap_create_config(apr_pool_t *p, server_rec *s);
-
-
-/*
- * Some definitions to help between various versions of apache.
- */
-
-#ifndef DOCTYPE_HTML_2_0
-#define DOCTYPE_HTML_2_0 "<!DOCTYPE HTML PUBLIC \"-//IETF//" \
- "DTD HTML 2.0//EN\">\n"
-#endif
-
-#ifndef DOCTYPE_HTML_3_2
-#define DOCTYPE_HTML_3_2 "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
- "DTD HTML 3.2 Final//EN\">\n"
-#endif
-
-#ifndef DOCTYPE_HTML_4_0S
-#define DOCTYPE_HTML_4_0S "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
- "DTD HTML 4.0//EN\"\n" \
- "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
-#endif
-
-#ifndef DOCTYPE_HTML_4_0T
-#define DOCTYPE_HTML_4_0T "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
- "DTD HTML 4.0 Transitional//EN\"\n" \
- "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n"
-#endif
-
-#ifndef DOCTYPE_HTML_4_0F
-#define DOCTYPE_HTML_4_0F "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
- "DTD HTML 4.0 Frameset//EN\"\n" \
- "\"http://www.w3.org/TR/REC-html40/frameset.dtd\">\n"
-#endif
-
-/*
- * Status Handler
- * --------------
- *
- * This handler generates a status page about the current performance of
- * the LDAP cache. It is enabled as follows:
- *
- * <Location /ldap-status>
- * SetHandler ldap-status
- * </Location>
- *
- */
-int util_ldap_handler(request_rec *r)
-{
-
- r->allowed |= (1 << M_GET);
- if (r->method_number != M_GET)
- return DECLINED;
-
- if (strcmp(r->handler, "ldap-status")) {
- return DECLINED;
- }
-
- r->content_type = "text/html";
- if (r->header_only)
- return OK;
-
- ap_rputs(DOCTYPE_HTML_3_2
- "<html><head><title>LDAP Cache Information</title></head>\n", r);
- ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information</h1>\n", r);
-
- ap_rputs("<p>\n"
- "<table border='0'>\n"
- "<tr bgcolor='#000000'>\n"
- "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
- "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
- "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
- "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
- "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
- "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
- "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
- "</tr>\n", r
- );
-
- ap_rputs(util_ald_cache_display(r->pool), r);
-
- ap_rputs("</table>\n</p>\n", r);
-
- return OK;
-}
-
-/* ------------------------------------------------------------------ */
-
-
-/*
- * Closes an LDAP connection by unlocking it. The next time
- * util_ldap_connection_find() is called this connection will be
- * available for reuse.
- */
-void util_ldap_connection_close(util_ldap_connection_t *ldc)
-{
-
- /*
- * QUESTION:
- *
- * Is it safe leaving bound connections floating around between the
- * different modules? Keeping the user bound is a performance boost,
- * but it is also a potential security problem - maybe.
- *
- * For now we unbind the user when we finish with a connection, but
- * we don't have to...
- */
-
- /* mark our connection as available for reuse */
- apr_thread_mutex_unlock(ldc->lock);
-
-}
-
-
-/*
- * Destroys an LDAP connection by unbinding. This function is registered
- * with the pool cleanup function - causing the LDAP connections to be
- * shut down cleanly on graceful restart.
- */
-apr_status_t util_ldap_connection_destroy(void *param)
-{
- util_ldap_connection_t *ldc = param;
-
- /* unbinding from the LDAP server */
- if (ldc->ldap) {
- ldap_unbind_s(ldc->ldap);
- ldc->bound = 0;
- ldc->ldap = NULL;
- }
-
- /* release the lock we were using */
- apr_thread_mutex_unlock(ldc->lock);
-
- return APR_SUCCESS;
-}
-
-
-/*
- * Connect to the LDAP server and binds. Does not connect if already
- * connected (i.e. ldc->ldap is non-NULL.) Does not bind if already bound.
- *
- * Returns LDAP_SUCCESS on success; and an error code on failure
- */
-int util_ldap_connection_open(util_ldap_connection_t *ldc)
-{
- int result = 0;
- int failures = 0;
-
-
-start_over:
- if (failures++ > 10) {
- /* too many failures - leave */
- return result;
- }
-
- if (!ldc->ldap) {
- ldc->bound = 0;
-
- /* opening connection to LDAP server */
- if ((ldc->ldap = ldap_init(ldc->host, ldc->port)) == NULL) {
- /* couldn't connect */
- ldc->reason = "ldap_init() failed";
- return -1;
- }
-
- /* add the cleanup to the pool */
- apr_pool_cleanup_register(ldc->pool, ldc,
- util_ldap_connection_destroy,
- apr_pool_cleanup_null);
-
- /* Set the alias dereferencing option */
-#if LDAP_VERSION_MAX == 2
- ldc->ldap->ld_deref = ldc->deref;
-#else
- result = ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &(ldc->deref));
- if (result != LDAP_SUCCESS) {
- /* setting LDAP dereference option failed */
- /* we ignore this error */
- }
-#endif /* LDAP_VERSION_MAX */
-
-#ifdef APU_HAS_LDAP_NETSCAPE_SSL
- if (ldc->netscapessl) {
- if (!ldc->certdb) {
- /* secure LDAP requested, but no CA cert defined */
- ldc->reason = "secure LDAP requested, but no CA cert defined";
- return -1;
- } else {
- result = ldapssl_install_routines(ldc->ldap);
- if (result != LDAP_SUCCESS) {
- /* SSL initialisation failed */
- ldc->reason = "ldapssl_install_routines() failed";
- return result;
- }
- result = ldap_set_option(ldc->ldap, LDAP_OPT_SSL, LDAP_OPT_ON);
- if (result != LDAP_SUCCESS) {
- /* SSL option failed */
- ldc->reason = "ldap_set_option() failed trying to set LDAP_OPT_SSL";
- return result;
- }
- }
- }
-#endif /* APU_HAS_LDAP_NETSCAPE_SSL */
-
-#ifdef APU_HAS_LDAP_STARTTLS
- if (ldc->starttls) {
- int version = LDAP_VERSION3;
-
- /* Also we have to set the connection to use protocol version 3,
- * since we're using TLS. */
- if ((result = ldap_set_option(ldc->ldap, LDAP_OPT_PROTOCOL_VERSION,
- &version)) != LDAP_SUCCESS) {
- /* setting LDAP version failed - ignore error */
- }
-
- /*
- * In util_ldap_connection_find, we compare ldc->withtls to
- * sec->starttls to see if we have a cache match. On the off
- * chance that apache's config processing rotines set starttls to
- * some other true value besides 1, we set it to 1 here to ensure
- * that the comparison succeeds.
- */
- ldc->starttls = 1;
-
- result = ldap_start_tls_s(ldc->ldap, NULL, NULL);
- if (result != LDAP_SUCCESS) {
- /* start TLS failed */
- ldc->withtls = 0;
- ldc->reason = "ldap_start_tls_s() failed";
- return result;
- }
- ldc->withtls = 1;
- } else {
- ldc->withtls = 0;
- }
-#endif /* APU_HAS_LDAP_STARTTLS */
- }
-
- /*
- * At this point the LDAP connection is guaranteed alive. If bound says
- * that we're bound already, we can just return.
- */
- if (ldc->bound) {
- ldc->reason = "LDAP connection open successful (already bound)";
- return LDAP_SUCCESS;
- }
-
- /*
- * Now bind with the username/password provided by the
- * configuration. It will be an anonymous bind if no u/p was
- * provided.
- */
- if ((result = ldap_simple_bind_s(ldc->ldap, ldc->binddn, ldc->bindpw))
- == LDAP_SERVER_DOWN) {
- /* couldn't connect - try again */
- ldc->reason = "ldap_simple_bind_s() failed with server down";
- goto start_over;
- }
-
- if (result != LDAP_SUCCESS) {
- /* LDAP fatal error occured */
- ldc->reason = "ldap_simple_bind_s() failed";
- return result;
- }
-
- /* note how we are bound */
- ldc->bound = 1;
-
- ldc->reason = "LDAP connection open successful";
- return LDAP_SUCCESS;
-}
-
-
-/*
- * Find an existing ldap connection struct that matches the
- * provided ldap connection parameters.
- *
- * If not found in the cache, a new ldc structure will be allocated from st->pool
- * and returned to the caller. If found in the cache, a pointer to the existing
- * ldc structure will be returned.
- */
-util_ldap_connection_t *util_ldap_connection_find(request_rec *r, const char *host, int port,
- const char *binddn, const char *bindpw, deref_options deref,
- int netscapessl, int starttls)
-{
- struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
-
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
- &ldap_module);
-
-
- /* mutex lock this function */
- if (!st->mutex) {
- apr_thread_mutex_create(&st->mutex, APR_THREAD_MUTEX_DEFAULT, st->pool);
- }
- apr_thread_mutex_lock(st->mutex);
-
- /* Search for an exact connection match in the list that is not
- * being used.
- */
- for (l=st->connections,p=NULL; l; l=l->next) {
- if ( (APR_SUCCESS == apr_thread_mutex_trylock(l->lock))
- && l->port == port
- && strcmp(l->host, host) == 0
- && ( (!l->binddn && !binddn) || (l->binddn && binddn && !strcmp(l->binddn, binddn)) )
- && ( (!l->bindpw && !bindpw) || (l->bindpw && bindpw && !strcmp(l->bindpw, bindpw)) )
- && l->deref == deref
-#ifdef APU_HAS_LDAP_NETSCAPE_SSL
- && l->netscapessl == netscapessl
-#endif
-#ifdef APU_HAS_LDAP_STARTTLS
- && l->withtls == starttls
-#endif
- )
- break;
- p = l;
- }
-
- /* If nothing found, search again, but we don't care about the
- * binddn and bindpw this time.
- */
- if (!l) {
- for (l=st->connections,p=NULL; l; l=l->next) {
- if ( (APR_SUCCESS == apr_thread_mutex_trylock(l->lock))
- && l->port == port
- && strcmp(l->host, host) == 0
- && l->deref == deref
-#ifdef APU_HAS_LDAP_NETSCAPE_SSL
- && l->netscapessl == netscapessl
-#endif
-#ifdef APU_HAS_LDAP_STARTTLS
- && l->withtls == starttls
-#endif
- ) {
- /* the bind credentials have changed */
- l->bound = 0;
- l->binddn = apr_pstrdup(st->pool, binddn);
- l->bindpw = apr_pstrdup(st->pool, bindpw);
- break;
- }
- p = l;
- }
- }
-
-/* artificially disable cache */
-//l = NULL;
-
- /* If no connection what found after the second search, we
- * must create one.
- */
- if (!l) {
-
- /*
- * Add the new connection entry to the linked list. Note that we
- * don't actually establish an LDAP connection yet; that happens
- * the first time authentication is requested.
- */
- /* create the details to the pool in st */
- l = apr_pcalloc(st->pool, sizeof(util_ldap_connection_t));
- apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, st->pool);
- apr_thread_mutex_lock(l->lock);
- l->pool = st->pool;
- l->bound = 0;
- l->host = apr_pstrdup(st->pool, host);
- l->port = port;
- l->deref = deref;
- l->binddn = apr_pstrdup(st->pool, binddn);
- l->bindpw = apr_pstrdup(st->pool, bindpw);
- l->netscapessl = netscapessl;
- l->starttls = starttls;
- l->withtls = 0;
-
- if (p) {
- p->next = l;
- }
- else {
- st->connections = l;
- }
- }
-
- apr_thread_mutex_unlock(st->mutex);
- return l;
-}
-
-/* ------------------------------------------------------------------ */
-
-/*
- * Compares two DNs to see if they're equal. The only way to do this correctly is to
- * search for the dn and then do ldap_get_dn() on the result. This should match the
- * initial dn, since it would have been also retrieved with ldap_get_dn(). This is
- * expensive, so if the configuration value compare_dn_on_server is
- * false, just does an ordinary strcmp.
- *
- * The lock for the ldap cache should already be acquired.
- */
-int util_ldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc,
- const char *url, const char *dn, const char *reqdn,
- int compare_dn_on_server)
-{
- int result = 0;
- util_url_node_t *curl;
- util_url_node_t curnode;
- util_dn_compare_node_t *node;
- util_dn_compare_node_t newnode;
- int failures = 0;
- LDAPMessage *res, *entry;
- char *searchdn;
-
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
- &ldap_module);
-
-
- /* read lock this function */
- if (!util_ldap_cache_lock) {
- apr_thread_rwlock_create(&util_ldap_cache_lock, st->pool);
- }
-
- /* get cache entry (or create one) */
- apr_thread_rwlock_wrlock(util_ldap_cache_lock);
- curnode.url = url;
- curl = util_ald_cache_fetch(util_ldap_cache, &curnode);
- if (curl == NULL) {
- curl = util_ald_create_caches(st, url);
- }
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
- /* a simple compare? */
- if (!compare_dn_on_server) {
- /* unlock this read lock */
- if (strcmp(dn, reqdn)) {
- ldc->reason = "DN Comparison FALSE (direct strcmp())";
- return LDAP_COMPARE_FALSE;
- }
- else {
- ldc->reason = "DN Comparison TRUE (direct strcmp())";
- return LDAP_COMPARE_TRUE;
- }
- }
-
- /* no - it's a server side compare */
- apr_thread_rwlock_rdlock(util_ldap_cache_lock);
-
- /* is it in the compare cache? */
- newnode.reqdn = (char *)reqdn;
- node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode);
- if (node != NULL) {
- /* If it's in the cache, it's good */
- /* unlock this read lock */
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
- ldc->reason = "DN Comparison TRUE (cached)";
- return LDAP_COMPARE_TRUE;
- }
-
- /* unlock this read lock */
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
-start_over:
- if (failures++ > 10) {
- /* too many failures */
- return result;
- }
-
- /* make a server connection */
- if (LDAP_SUCCESS != (result = util_ldap_connection_open(ldc))) {
- /* connect to server failed */
- return result;
- }
-
- /* search for reqdn */
- if ((result = ldap_search_ext_s(ldc->ldap, const_cast(reqdn), LDAP_SCOPE_BASE,
- "(objectclass=*)", NULL, 1,
- NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) {
- util_ldap_connection_close(ldc);
- ldc->reason = "DN Comparison ldap_search_ext_s() failed with server down";
- goto start_over;
- }
- if (result != LDAP_SUCCESS) {
- /* search for reqdn failed - no match */
- ldc->reason = "DN Comparison ldap_search_ext_s() failed";
- return result;
- }
-
- entry = ldap_first_entry(ldc->ldap, res);
- searchdn = ldap_get_dn(ldc->ldap, entry);
-
- ldap_msgfree(res);
- if (strcmp(dn, searchdn) != 0) {
- /* compare unsuccessful */
- ldc->reason = "DN Comparison FALSE (checked on server)";
- result = LDAP_COMPARE_FALSE;
- }
- else {
- /* compare successful - add to the compare cache */
- apr_thread_rwlock_rdlock(util_ldap_cache_lock);
- newnode.reqdn = (char *)reqdn;
- newnode.dn = (char *)dn;
- util_ald_cache_insert(curl->dn_compare_cache, &newnode);
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
- ldc->reason = "DN Comparison TRUE (checked on server)";
- result = LDAP_COMPARE_TRUE;
- }
- ldap_memfree(searchdn);
- return result;
-
-}
-
-/*
- * Does an generic ldap_compare operation. It accepts a cache that it will use
- * to lookup the compare in the cache. We cache two kinds of compares
- * (require group compares) and (require user compares). Each compare has a different
- * cache node: require group includes the DN; require user does not because the
- * require user cache is owned by the
- *
- */
-int util_ldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc,
- const char *url, const char *dn,
- const char *attrib, const char *value)
-{
- int result = 0;
- util_url_node_t *curl;
- util_url_node_t curnode;
- util_compare_node_t *compare_nodep;
- util_compare_node_t the_compare_node;
- apr_time_t curtime;
- int failures = 0;
-
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
- &ldap_module);
-
-
- /* read lock this function */
- if (!util_ldap_cache_lock) {
- apr_thread_rwlock_create(&util_ldap_cache_lock, st->pool);
- }
-
- /* get cache entry (or create one) */
- apr_thread_rwlock_wrlock(util_ldap_cache_lock);
- curnode.url = url;
- curl = util_ald_cache_fetch(util_ldap_cache, &curnode);
- if (curl == NULL) {
- curl = util_ald_create_caches(st, url);
- }
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
- /* make a comparison to the cache */
- apr_thread_rwlock_rdlock(util_ldap_cache_lock);
- curtime = apr_time_now();
-
- the_compare_node.dn = (char *)dn;
- the_compare_node.attrib = (char *)attrib;
- the_compare_node.value = (char *)value;
- the_compare_node.result = 0;
-
- compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node);
-
- if (compare_nodep != NULL) {
- /* found it... */
- if (curtime - compare_nodep->lastcompare > st->compare_cache_ttl) {
- /* ...but it is too old */
- util_ald_cache_remove(curl->compare_cache, compare_nodep);
- }
- else {
- /* ...and it is good */
- /* unlock this read lock */
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
- if (LDAP_COMPARE_TRUE == compare_nodep->result) {
- ldc->reason = "Comparison true (cached)";
- return compare_nodep->result;
- }
- else if (LDAP_COMPARE_FALSE == compare_nodep->result) {
- ldc->reason = "Comparison false (cached)";
- return compare_nodep->result;
- }
- else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) {
- ldc->reason = "Comparison no such attribute (cached)";
- return compare_nodep->result;
- }
- else {
- ldc->reason = "Comparison undefined (cached)";
- return compare_nodep->result;
- }
- }
- }
- /* unlock this read lock */
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
-
-start_over:
- if (failures++ > 10) {
- /* too many failures */
- return result;
- }
- if (LDAP_SUCCESS != (result = util_ldap_connection_open(ldc))) {
- /* connect failed */
- return result;
- }
-
- if ((result = ldap_compare_s(ldc->ldap, const_cast(dn),
- const_cast(attrib), const_cast(value)))
- == LDAP_SERVER_DOWN) {
- /* connection failed - try again */
- util_ldap_connection_close(ldc);
- ldc->reason = "ldap_compare_s() failed with server down";
- goto start_over;
- }
-
- ldc->reason = "Comparison complete";
- if ((LDAP_COMPARE_TRUE == result) ||
- (LDAP_COMPARE_FALSE == result) ||
- (LDAP_NO_SUCH_ATTRIBUTE == result)) {
- /* compare completed; caching result */
- apr_thread_rwlock_wrlock(util_ldap_cache_lock);
- the_compare_node.lastcompare = curtime;
- the_compare_node.result = result;
- util_ald_cache_insert(curl->compare_cache, &the_compare_node);
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
- if (LDAP_COMPARE_TRUE == result) {
- ldc->reason = "Comparison true (adding to cache)";
- return LDAP_COMPARE_TRUE;
- }
- else if (LDAP_COMPARE_FALSE == result) {
- ldc->reason = "Comparison false (adding to cache)";
- return LDAP_COMPARE_FALSE;
- }
- else {
- ldc->reason = "Comparison no such attribute (adding to cache)";
- return LDAP_NO_SUCH_ATTRIBUTE;
- }
- }
- return result;
-}
-
-int util_ldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc,
- const char *url, const char *basedn, int scope, char **attrs,
- const char *filter, const char *bindpw, const char **binddn,
- const char ***retvals)
-{
- const char **vals = NULL;
- int result = 0;
- LDAPMessage *res, *entry;
- char *dn;
- int count;
- int failures = 0;
- util_url_node_t *curl; /* Cached URL node */
- util_url_node_t curnode;
- util_search_node_t *search_nodep; /* Cached search node */
- util_search_node_t the_search_node;
- apr_time_t curtime;
-
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(r->server->module_config,
- &ldap_module);
-
- /* read lock this function */
- if (!util_ldap_cache_lock) {
- apr_thread_rwlock_create(&util_ldap_cache_lock, st->pool);
- }
-
- /* Get the cache node for this url */
- apr_thread_rwlock_wrlock(util_ldap_cache_lock);
- curnode.url = url;
- curl = (util_url_node_t *)util_ald_cache_fetch(util_ldap_cache, &curnode);
- if (curl == NULL) {
- curl = util_ald_create_caches(st, url);
- }
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
- apr_thread_rwlock_rdlock(util_ldap_cache_lock);
- the_search_node.username = filter;
- search_nodep = util_ald_cache_fetch(curl->search_cache, &the_search_node);
- if (search_nodep != NULL && search_nodep->bindpw) {
-
- /* found entry in search cache... */
- curtime = apr_time_now();
-
- /*
- * Remove this item from the cache if its expired, or if the
- * sent password doesn't match the storepassword.
- */
- if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) {
- /* ...but entry is too old */
- util_ald_cache_remove(curl->search_cache, search_nodep);
- }
- else if (strcmp(search_nodep->bindpw, bindpw) != 0) {
- /* ...but cached password doesn't match sent password */
- util_ald_cache_remove(curl->search_cache, search_nodep);
- }
- else {
- /* ...and entry is valid */
- *binddn = search_nodep->dn;
- *retvals = search_nodep->vals;
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
- ldc->reason = "Authentication successful (cached)";
- return LDAP_SUCCESS;
- }
- }
- /* unlock this read lock */
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
-
- /*
- * At this point, there is no valid cached search, so lets do the search.
- */
-
- /*
- * If any LDAP operation fails due to LDAP_SERVER_DOWN, control returns here.
- */
-start_over:
- if (failures++ > 10) {
- return result;
- }
- if (LDAP_SUCCESS != (result = util_ldap_connection_open(ldc))) {
- return result;
- }
-
- /* try do the search */
- if ((result = ldap_search_ext_s(ldc->ldap,
- basedn, scope,
- filter, attrs, 0,
- NULL, NULL, NULL, -1, &res)) == LDAP_SERVER_DOWN) {
- ldc->reason = "ldap_search_ext_s() for user failed with server down";
- goto start_over;
- }
-
- /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */
- if (result != LDAP_SUCCESS) {
- ldc->reason = "ldap_search_ext_s() for user failed";
- return result;
- }
-
- /*
- * We should have found exactly one entry; to find a different
- * number is an error.
- */
- count = ldap_count_entries(ldc->ldap, res);
- if (count != 1) {
- ldap_msgfree(res);
- ldc->reason = "User is not unique (search found two or more matches)";
- return LDAP_NO_SUCH_OBJECT;
- }
-
- entry = ldap_first_entry(ldc->ldap, res);
-
- /* Grab the dn, copy it into the pool, and free it again */
- dn = ldap_get_dn(ldc->ldap, entry);
- *binddn = apr_pstrdup(st->pool, dn);
- ldap_memfree(dn);
-
- /*
- * A bind to the server with an empty password always succeeds, so
- * we check to ensure that the password is not empty. This implies
- * that users who actually do have empty passwords will never be
- * able to authenticate with this module. I don't see this as a big
- * problem.
- */
- if (strlen(bindpw) <= 0) {
- ldap_msgfree(res);
- ldc->reason = "Empty password not allowed";
- return LDAP_INVALID_CREDENTIALS;
- }
-
- /*
- * Attempt to bind with the retrieved dn and the password. If the bind
- * fails, it means that the password is wrong (the dn obviously
- * exists, since we just retrieved it)
- */
- if ((result =
- ldap_simple_bind_s(ldc->ldap, *binddn, bindpw)) ==
- LDAP_SERVER_DOWN) {
- ldc->reason = "ldap_simple_bind_s() to check user credentials failed with server down";
- goto start_over;
- }
-
- /* failure? if so - return */
- if (result != LDAP_SUCCESS) {
- ldc->reason = "ldap_simple_bind_s() to check user credentials failed";
- return result;
- }
-
- /*
- * Get values for the provided attributes.
- */
- if (attrs) {
- int k = 0;
- int i = 0;
- while (attrs[k++]);
- vals = apr_pcalloc(r->pool, sizeof(char *) * (k+1));
- while (attrs[i]) {
- char **values;
- int j = 0;
- char *str = NULL;
- /* get values */
- values = ldap_get_values(ldc->ldap, entry, attrs[i]);
- while (values && values[j]) {
- str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL) : apr_pstrdup(r->pool, values[j]);
- j++;
- }
- vals[i] = str;
- i++;
- }
- *retvals = vals;
- }
-
- /*
- * Add the new username to the search cache.
- */
- apr_thread_rwlock_wrlock(util_ldap_cache_lock);
- the_search_node.username = filter;
- the_search_node.dn = *binddn;
- the_search_node.bindpw = bindpw;
- the_search_node.lastbind = apr_time_now();
- the_search_node.vals = vals;
- util_ald_cache_insert(curl->search_cache, &the_search_node);
- ldap_msgfree(res);
- apr_thread_rwlock_unlock(util_ldap_cache_lock);
-
- ldc->reason = "Authentication successful";
- return LDAP_SUCCESS;
-}
-
-#endif /* APU_HAS_LDAP */
-
-
-
-/* ---------------------------------------- */
-/* config directives */
-
-
-static const char *util_ldap_set_cache_bytes(cmd_parms *cmd, void *dummy, const char *bytes)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
-
- st->cache_bytes = atol(bytes);
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "[%d] ldap cache: Setting shared memory cache size to %d bytes.",
- getpid(), st->cache_bytes);
-
- return NULL;
-}
-
-static const char *util_ldap_set_cache_ttl(cmd_parms *cmd, void *dummy, const char *ttl)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
-
- st->search_cache_ttl = atol(ttl) * 1000000;
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "[%d] ldap cache: Setting cache TTL to %ld microseconds.",
- getpid(), st->search_cache_ttl);
-
- return NULL;
-}
-
-static const char *util_ldap_set_cache_entries(cmd_parms *cmd, void *dummy, const char *size)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
-
-
- st->search_cache_size = atol(size);
- if (st->search_cache_size < 0) {
- st->search_cache_size = 0;
- }
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "[%d] ldap cache: Setting search cache size to %ld entries.",
- getpid(), st->search_cache_size);
-
- return NULL;
-}
-
-static const char *util_ldap_set_opcache_ttl(cmd_parms *cmd, void *dummy, const char *ttl)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
-
- st->compare_cache_ttl = atol(ttl) * 1000000;
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "[%d] ldap cache: Setting operation cache TTL to %ld microseconds.",
- getpid(), st->compare_cache_ttl);
-
- return NULL;
-}
-
-static const char *util_ldap_set_opcache_entries(cmd_parms *cmd, void *dummy, const char *size)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
-
- st->compare_cache_size = atol(size);
- if (st->compare_cache_size < 0) {
- st->compare_cache_size = 0;
- }
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "[%d] ldap cache: Setting operation cache size to %ld entries.",
- getpid(), st->compare_cache_size);
-
- return NULL;
-}
-
-#ifdef APU_HAS_LDAPSSL_CLIENT_INIT
-static const char *util_ldap_set_certdbpath(cmd_parms *cmd, void *dummy, const char *path)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
- &ldap_module);
-
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, cmd->server,
- "[%d] ldap cache: Setting LDAP SSL client certificate dbpath to %s.",
- getpid(), path);
-
- st->have_certdb = 1;
- if (ldapssl_client_init(path, NULL) != 0) {
- return "Could not initialize SSL client";
- }
- else {
- return NULL;
- }
-}
-#endif
-
-void *util_ldap_create_config(apr_pool_t *p, server_rec *s)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)apr_pcalloc(p, sizeof(util_ldap_state_t));
-
- st->pool = p;
-
- st->cache_bytes = 100000;
- st->search_cache_ttl = 600000000;
- st->search_cache_size = 1024;
- st->compare_cache_ttl = 600000000;
- st->compare_cache_size = 1024;
-
- st->connections = NULL;
-#ifdef APU_HAS_LDAP_NETSCAPE_SSL
- st->have_certdb = 0;
-#endif
-
- return st;
-}
-
-static void util_ldap_init_module(apr_pool_t *pool, server_rec *s)
-{
- util_ldap_state_t *st =
- (util_ldap_state_t *)ap_get_module_config(s->module_config,
- &ldap_module);
-
- apr_status_t result = util_ldap_cache_init(pool, st->cache_bytes);
- char buf[MAX_STRING_LEN];
-
- apr_strerror(result, buf, sizeof(buf));
- ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, result, s,
- "[%d] ldap cache init: %s",
- getpid(), buf);
-}
-
-
-command_rec util_ldap_cmds[] = {
- AP_INIT_TAKE1("LDAPSharedCacheSize", util_ldap_set_cache_bytes, NULL, RSRC_CONF,
- "Sets the size of the shared memory cache in bytes. "
- "Zero means disable the shared memory cache. Defaults to 100KB."),
-
- AP_INIT_TAKE1("LDAPCacheEntries", util_ldap_set_cache_entries, NULL, RSRC_CONF,
- "Sets the maximum number of entries that are possible in the LDAP "
- "search cache. "
- "Zero means no limit; -1 disables the cache. Defaults to 1024 entries."),
-
- AP_INIT_TAKE1("LDAPCacheTTL", util_ldap_set_cache_ttl, NULL, RSRC_CONF,
- "Sets the maximum time (in seconds) that an item can be cached in the LDAP "
- "search cache. Zero means no limit. Defaults to 600 seconds (10 minutes)."),
-
- AP_INIT_TAKE1("LDAPOpCacheEntries", util_ldap_set_opcache_entries, NULL, RSRC_CONF,
- "Sets the maximum number of entries that are possible in the LDAP "
- "compare cache. "
- "Zero means no limit; -1 disables the cache. Defaults to 1024 entries."),
-
- AP_INIT_TAKE1("LDAPOpCacheTTL", util_ldap_set_opcache_ttl, NULL, RSRC_CONF,
- "Sets the maximum time (in seconds) that an item is cached in the LDAP "
- "operation cache. Zero means no limit. Defaults to 600 seconds (10 minutes)."),
-
-#ifdef APU_HAS_LDAPSSL_CLIENT_INIT
- AP_INIT_TAKE1("LDAPCertDBPath", util_ldap_set_certdbpath, NULL, RSRC_CONF,
- "Specifies the file containing Certificate Authority certificates "
- "for validating secure LDAP server certificates. This file must be the "
- "cert7.db database used by Netscape Communicator"),
-#endif
-
- {NULL}
-};
-
-static void util_ldap_register_hooks(apr_pool_t *p)
-{
- ap_hook_child_init(util_ldap_init_module, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_handler(util_ldap_handler, NULL, NULL, APR_HOOK_MIDDLE);
-}
-
-module ldap_module = {
- STANDARD20_MODULE_STUFF,
- NULL, /* dir config creater */
- NULL, /* dir merger --- default is to override */
- util_ldap_create_config, /* server config */
- NULL, /* merge server config */
- util_ldap_cmds, /* command table */
- util_ldap_register_hooks, /* set up request processing hooks */
-};
diff --git a/modules/experimental/util_ldap.def b/modules/experimental/util_ldap.def
deleted file mode 100644
index d1fac89b35..0000000000
--- a/modules/experimental/util_ldap.def
+++ /dev/null
@@ -1,6 +0,0 @@
-EXPORT ldap_module
-EXPORT util_ldap_connection_find
-EXPORT util_ldap_connection_close
-EXPORT util_ldap_cache_checkuserid
-EXPORT util_ldap_cache_compare
-EXPORT util_ldap_cache_comparedn
diff --git a/modules/experimental/util_ldap_cache.c b/modules/experimental/util_ldap_cache.c
deleted file mode 100644
index 9d9844ddd6..0000000000
--- a/modules/experimental/util_ldap_cache.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2001 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- */
-
-/*
- * util_ldap_cache.c: LDAP cache things
- *
- * Original code from auth_ldap module for Apache v1.3:
- * Copyright 1998, 1999 Enbridge Pipelines Inc.
- * Copyright 1999-2001 Dave Carrigan
- */
-
-#include <apr_ldap.h>
-#include "util_ldap.h"
-#include "util_ldap_cache.h"
-
-#ifdef APU_HAS_LDAP
-
-
-
-
-/* ------------------------------------------------------------------ */
-
-unsigned long util_ldap_url_node_hash(void *n)
-{
- util_url_node_t *node = (util_url_node_t *)n;
- return util_ald_hash_string(1, node->url);
-}
-
-int util_ldap_url_node_compare(void *a, void *b)
-{
- util_url_node_t *na = (util_url_node_t *)a;
- util_url_node_t *nb = (util_url_node_t *)b;
-
- return(strcmp(na->url, nb->url) == 0);
-}
-
-void *util_ldap_url_node_copy(void *c)
-{
- util_url_node_t *n = (util_url_node_t *)c;
- util_url_node_t *node = (util_url_node_t *)util_ald_alloc(sizeof(util_url_node_t));
-
- if (node) {
- if (!(node->url = util_ald_strdup(n->url))) {
- util_ald_free(node->url);
- return NULL;
- }
- node->search_cache = n->search_cache;
- node->compare_cache = n->compare_cache;
- node->dn_compare_cache = n->dn_compare_cache;
- return node;
- }
- else {
- return NULL;
- }
-}
-
-void util_ldap_url_node_free(void *n)
-{
- util_url_node_t *node = (util_url_node_t *)n;
-
- util_ald_free(node->url);
- util_ald_destroy_cache(node->search_cache);
- util_ald_destroy_cache(node->compare_cache);
- util_ald_destroy_cache(node->dn_compare_cache);
- util_ald_free(node);
-}
-
-/* ------------------------------------------------------------------ */
-
-/* Cache functions for search nodes */
-unsigned long util_ldap_search_node_hash(void *n)
-{
- util_search_node_t *node = (util_search_node_t *)n;
- return util_ald_hash_string(1, ((util_search_node_t *)(node))->username);
-}
-
-int util_ldap_search_node_compare(void *a, void *b)
-{
- return(strcmp(((util_search_node_t *)a)->username,
- ((util_search_node_t *)b)->username) == 0);
-}
-
-void *util_ldap_search_node_copy(void *c)
-{
- util_search_node_t *node = (util_search_node_t *)c;
- util_search_node_t *newnode = util_ald_alloc(sizeof(util_search_node_t));
-
- /* safety check */
- if (newnode) {
-
- /* copy vals */
- if (node->vals) {
- int k = 0;
- int i = 0;
- while (node->vals[k++]);
- if (!(newnode->vals = util_ald_alloc(sizeof(char *) * (k+1)))) {
- util_ldap_search_node_free(newnode);
- return NULL;
- }
- while (node->vals[i]) {
- if (!(newnode->vals[i] = util_ald_strdup(node->vals[i]))) {
- util_ldap_search_node_free(newnode);
- return NULL;
- }
- i++;
- }
- }
- else {
- newnode->vals = NULL;
- }
- if (!(newnode->username = util_ald_strdup(node->username)) ||
- !(newnode->dn = util_ald_strdup(node->dn)) ||
- !(newnode->bindpw = util_ald_strdup(node->bindpw)) ) {
- util_ldap_search_node_free(newnode);
- return NULL;
- }
- newnode->lastbind = node->lastbind;
-
- }
- return (void *)newnode;
-}
-
-void util_ldap_search_node_free(void *n)
-{
- int i = 0;
- util_search_node_t *node = (util_search_node_t *)n;
- if (node->vals) {
- while (node->vals[i]) {
- util_ald_free(node->vals[i++]);
- }
- util_ald_free(node->vals);
- }
- util_ald_free(node->username);
- util_ald_free(node->dn);
- util_ald_free(node->bindpw);
- util_ald_free(node);
-}
-
-/* ------------------------------------------------------------------ */
-
-unsigned long util_ldap_compare_node_hash(void *n)
-{
- util_compare_node_t *node = (util_compare_node_t *)n;
- return util_ald_hash_string(3, node->dn, node->attrib, node->value);
-}
-
-int util_ldap_compare_node_compare(void *a, void *b)
-{
- util_compare_node_t *na = (util_compare_node_t *)a;
- util_compare_node_t *nb = (util_compare_node_t *)b;
- return (strcmp(na->dn, nb->dn) == 0 &&
- strcmp(na->attrib, nb->attrib) == 0 &&
- strcmp(na->value, nb->value) == 0);
-}
-
-void *util_ldap_compare_node_copy(void *c)
-{
- util_compare_node_t *n = (util_compare_node_t *)c;
- util_compare_node_t *node = (util_compare_node_t *)util_ald_alloc(sizeof(util_compare_node_t));
-
- if (node) {
- if (!(node->dn = util_ald_strdup(n->dn)) ||
- !(node->attrib = util_ald_strdup(n->attrib)) ||
- !(node->value = util_ald_strdup(n->value))) {
- util_ldap_compare_node_free(node);
- return NULL;
- }
- node->lastcompare = n->lastcompare;
- node->result = n->result;
- return node;
- }
- else {
- return NULL;
- }
-}
-
-void util_ldap_compare_node_free(void *n)
-{
- util_compare_node_t *node = (util_compare_node_t *)n;
- util_ald_free(node->dn);
- util_ald_free(node->attrib);
- util_ald_free(node->value);
- util_ald_free(node);
-}
-
-/* ------------------------------------------------------------------ */
-
-unsigned long util_ldap_dn_compare_node_hash(void *n)
-{
- return util_ald_hash_string(1, ((util_dn_compare_node_t *)n)->reqdn);
-}
-
-int util_ldap_dn_compare_node_compare(void *a, void *b)
-{
- return (strcmp(((util_dn_compare_node_t *)a)->reqdn,
- ((util_dn_compare_node_t *)b)->reqdn) == 0);
-}
-
-void *util_ldap_dn_compare_node_copy(void *c)
-{
- util_dn_compare_node_t *n = (util_dn_compare_node_t *)c;
- util_dn_compare_node_t *node = (util_dn_compare_node_t *)util_ald_alloc(sizeof(util_dn_compare_node_t));
- if (node) {
- if (!(node->reqdn = util_ald_strdup(n->reqdn)) ||
- !(node->dn = util_ald_strdup(n->dn))) {
- util_ldap_dn_compare_node_free(node);
- return NULL;
- }
- return node;
- }
- else {
- return NULL;
- }
-}
-
-void util_ldap_dn_compare_node_free(void *n)
-{
- util_dn_compare_node_t *node = (util_dn_compare_node_t *)n;
- util_ald_free(node->reqdn);
- util_ald_free(node->dn);
- util_ald_free(node);
-}
-
-
-/* ------------------------------------------------------------------ */
-apr_status_t util_ldap_cache_child_kill(void *data);
-apr_status_t util_ldap_cache_module_kill(void *data);
-
-apr_status_t util_ldap_cache_module_kill(void *data)
-{
-#if APR_HAS_SHARED_MEMORY
- if (util_ldap_shm != NULL) {
- apr_status_t result = apr_shm_destroy(util_ldap_shm);
- util_ldap_shm = NULL;
- return result;
- }
-#endif
- return APR_SUCCESS;
-}
-
-apr_status_t util_ldap_cache_init(apr_pool_t *pool, apr_size_t reqsize)
-{
- apr_status_t result = APR_SUCCESS;
- apr_pool_cleanup_register(pool, NULL, util_ldap_cache_module_kill, apr_pool_cleanup_null);
-
-#if APR_HAS_SHARED_MEMORY
- result = apr_shm_init(&util_ldap_shm, reqsize, "/tmp/ldap_cache", pool);
-#endif
- util_ldap_cache = util_ald_create_cache(50,
- util_ldap_url_node_hash,
- util_ldap_url_node_compare,
- util_ldap_url_node_copy,
- util_ldap_url_node_free);
- return result;
-}
-
-
-#endif /* APU_HAS_LDAP */
diff --git a/modules/experimental/util_ldap_cache.h b/modules/experimental/util_ldap_cache.h
deleted file mode 100644
index 8e71799734..0000000000
--- a/modules/experimental/util_ldap_cache.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2001 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- */
-
-
-#ifndef APU_LDAP_CACHE_H
-#define APU_LDAP_CACHE_H
-
-/*
- * This switches LDAP support on or off.
- */
-
-/* this whole thing disappears if LDAP is not enabled */
-#ifdef APU_HAS_LDAP
-
-
-/*
- * LDAP Cache Manager
- */
-
-#include <apr_shm.h>
-
-typedef struct util_cache_node_t {
- void *payload; /* Pointer to the payload */
- time_t add_time; /* Time node was added to cache */
- struct util_cache_node_t *next;
-} util_cache_node_t;
-
-typedef struct util_ald_cache_t {
- unsigned long size; /* Size of cache array */
- unsigned long maxentries; /* Maximum number of cache entries */
- unsigned long numentries; /* Current number of cache entries */
- unsigned long fullmark; /* Used to keep track of when cache becomes 3/4 full */
- time_t marktime; /* Time that the cache became 3/4 full */
- unsigned long (*hash)(void *); /* Func to hash the payload */
- int (*compare)(void *, void *); /* Func to compare two payloads */
- void * (*copy)(void *); /* Func to alloc mem and copy payload to new mem */
- void (*free)(void *); /* Func to free mem used by the payload */
- util_cache_node_t **nodes;
-
- unsigned long numpurges; /* No. of times the cache has been purged */
- double avg_purgetime; /* Average time to purge the cache */
- time_t last_purge; /* Time of the last purge */
- unsigned long npurged; /* Number of elements purged in last purge. This is not
- obvious: it won't be 3/4 the size of the cache if
- there were a lot of expired entries. */
-
- unsigned long fetches; /* Number of fetches */
- unsigned long hits; /* Number of cache hits */
- unsigned long inserts; /* Number of inserts */
- unsigned long removes; /* Number of removes */
-} util_ald_cache_t;
-
-#if APR_HAS_SHARED_MEMORY
-apr_shmem_t *util_ldap_shm;
-#endif
-util_ald_cache_t *util_ldap_cache;
-apr_thread_rwlock_t *util_ldap_cache_lock;
-
-#ifndef WIN32
-#define ALD_MM_FILE_MODE ( S_IRUSR|S_IWUSR )
-#else
-#define ALD_MM_FILE_MODE ( _S_IREAD|_S_IWRITE )
-#endif
-
-
-/*
- * LDAP Cache
- */
-
-/*
- * Maintain a cache of LDAP URLs that the server handles. Each node in
- * the cache contains the search cache for that URL, and a compare cache
- * for the URL. The compare cash is populated when doing require group
- * compares.
- */
-typedef struct util_url_node_t {
- const char *url;
- util_ald_cache_t *search_cache;
- util_ald_cache_t *compare_cache;
- util_ald_cache_t *dn_compare_cache;
-} util_url_node_t;
-
-/*
- * We cache every successful search and bind operation, using the username
- * as the key. Each node in the cache contains the returned DN, plus the
- * password used to bind.
- */
-typedef struct util_search_node_t {
- const char *username; /* Cache key */
- const char *dn; /* DN returned from search */
- const char *bindpw; /* The most recently used bind password;
- NULL if the bind failed */
- apr_time_t lastbind; /* Time of last successful bind */
- const char **vals; /* Values of queried attributes */
-} util_search_node_t;
-
-/*
- * We cache every successful compare operation, using the DN, attrib, and
- * value as the key.
- */
-typedef struct util_compare_node_t {
- const char *dn; /* DN, attrib and value combine to be the key */
- const char *attrib;
- const char *value;
- apr_time_t lastcompare;
- int result;
-} util_compare_node_t;
-
-/*
- * We cache every successful compare dn operation, using the dn in the require
- * statement and the dn fetched based on the client-provided username.
- */
-typedef struct util_dn_compare_node_t {
- const char *reqdn; /* The DN in the require dn statement */
- const char *dn; /* The DN found in the search */
-} util_dn_compare_node_t;
-
-
-/*
- * Function prototypes for LDAP cache
- */
-
-/* util_ldap_cache.c */
-unsigned long util_ldap_url_node_hash(void *n);
-int util_ldap_url_node_compare(void *a, void *b);
-void *util_ldap_url_node_copy(void *c);
-void util_ldap_url_node_free(void *n);
-unsigned long util_ldap_search_node_hash(void *n);
-int util_ldap_search_node_compare(void *a, void *b);
-void *util_ldap_search_node_copy(void *c);
-void util_ldap_search_node_free(void *n);
-unsigned long util_ldap_compare_node_hash(void *n);
-int util_ldap_compare_node_compare(void *a, void *b);
-void *util_ldap_compare_node_copy(void *c);
-void util_ldap_compare_node_free(void *n);
-unsigned long util_ldap_dn_compare_node_hash(void *n);
-int util_ldap_dn_compare_node_compare(void *a, void *b);
-void *util_ldap_dn_compare_node_copy(void *c);
-void util_ldap_dn_compare_node_free(void *n);
-
-
-/* util_ldap_cache_mgr.c */
-
-void util_ald_free(const void *ptr);
-void *util_ald_alloc(unsigned long size);
-const char *util_ald_strdup(const char *s);
-unsigned long util_ald_hash_string(int nstr, ...);
-void util_ald_cache_purge(util_ald_cache_t *cache);
-util_url_node_t *util_ald_create_caches(util_ldap_state_t *s, const char *url);
-util_ald_cache_t *util_ald_create_cache(unsigned long maxentries,
- unsigned long (*hashfunc)(void *),
- int (*comparefunc)(void *, void *),
- void * (*copyfunc)(void *),
- void (*freefunc)(void *));
-void util_ald_destroy_cache(util_ald_cache_t *cache);
-void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload);
-void util_ald_cache_insert(util_ald_cache_t *cache, void *payload);
-void util_ald_cache_remove(util_ald_cache_t *cache, void *payload);
-char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache,
- char *name);
-
-#endif /* APU_HAS_LDAP */
-#endif /* APU_LDAP_CACHE_H */
diff --git a/modules/experimental/util_ldap_cache_mgr.c b/modules/experimental/util_ldap_cache_mgr.c
deleted file mode 100644
index 49eece8958..0000000000
--- a/modules/experimental/util_ldap_cache_mgr.c
+++ /dev/null
@@ -1,537 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2001 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
- * the documentation and/or other materials provided with the
- * 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
- * <http://www.apache.org/>.
- */
-
-/*
- * util_ldap_cache_mgr.c: LDAP cache manager things
- *
- * Original code from auth_ldap module for Apache v1.3:
- * Copyright 1998, 1999 Enbridge Pipelines Inc.
- * Copyright 1999-2001 Dave Carrigan
- */
-
-#include <apr_ldap.h>
-#include "util_ldap.h"
-#include "util_ldap_cache.h"
-#include <apr_strings.h>
-
-#ifdef APU_HAS_LDAP
-
-/* only here until strdup is gone */
-#include <string.h>
-
-/* here till malloc is gone */
-#include <stdlib.h>
-
-static const int primes[] =
-{
- 11,
- 19,
- 37,
- 73,
- 109,
- 163,
- 251,
- 367,
- 557,
- 823,
- 1237,
- 1861,
- 2777,
- 4177,
- 6247,
- 9371,
- 14057,
- 21089,
- 31627,
- 47431,
- 71143,
- 106721,
- 160073,
- 240101,
- 360163,
- 540217,
- 810343,
- 1215497,
- 1823231,
- 2734867,
- 4102283,
- 6153409,
- 9230113,
- 13845163,
- 0
-};
-
-void util_ald_free(const void *ptr)
-{
-#if APR_HAS_SHARED_MEMORY
- if (util_ldap_shm) {
- if (ptr)
- apr_shm_free(util_ldap_shm, (void *)ptr);
- } else {
- if (ptr)
- free((void *)ptr);
- }
-#else
- if (ptr)
- free((void *)ptr);
-#endif
-}
-
-void *util_ald_alloc(unsigned long size)
-{
- if (0 == size)
- return NULL;
-#if APR_HAS_SHARED_MEMORY
- if (util_ldap_shm) {
- return (void *)apr_shm_calloc(util_ldap_shm, size);
- } else {
- return (void *)calloc(sizeof(char), size);
- }
-#else
- return (void *)calloc(sizeof(char), size);
-#endif
-}
-
-const char *util_ald_strdup(const char *s)
-{
-#if APR_HAS_SHARED_MEMORY
- if (util_ldap_shm) {
- char *buf = apr_shm_malloc(util_ldap_shm, strlen(s)+1);
- if (buf) {
- strcpy(buf, s);
- return buf;
- }
- else {
- return NULL;
- }
- } else {
- return strdup(s);
- }
-#else
- return strdup(s);
-#endif
-}
-
-
-/*
- * Computes the hash on a set of strings. The first argument is the number
- * of strings to hash, the rest of the args are strings.
- * Algorithm taken from glibc.
- */
-unsigned long util_ald_hash_string(int nstr, ...)
-{
- int i;
- va_list args;
- unsigned long h=0, g;
- char *str, *p;
-
- va_start(args, nstr);
- for (i=0; i < nstr; ++i) {
- str = va_arg(args, char *);
- for (p = str; *p; ++p) {
- h = ( h << 4 ) + *p;
- if ( ( g = h & 0xf0000000 ) ) {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- }
- }
- va_end(args);
-
- return h;
-}
-
-
-/*
- Purges a cache that has gotten full. We keep track of the time that we
- added the entry that made the cache 3/4 full, then delete all entries
- that were added before that time. It's pretty simplistic, but time to
- purge is only O(n), which is more important.
-*/
-void util_ald_cache_purge(util_ald_cache_t *cache)
-{
- int i;
- util_cache_node_t *p, *q;
- apr_time_t t;
-
- if (!cache)
- return;
-
- cache->last_purge = apr_time_now();
- cache->npurged = 0;
- cache->numpurges++;
-
- for (i=0; i < cache->size; ++i) {
- p = cache->nodes[i];
- while (p != NULL) {
- if (p->add_time < cache->marktime) {
- q = p->next;
- (*cache->free)(p->payload);
- util_ald_free(p);
- cache->numentries--;
- cache->npurged++;
- p = q;
- }
- else {
- p = p->next;
- }
- }
- }
-
- t = apr_time_now();
- cache->avg_purgetime =
- ((t - cache->last_purge) + (cache->avg_purgetime * (cache->numpurges-1))) /
- cache->numpurges;
-}
-
-
-/*
- * create caches
- */
-util_url_node_t *util_ald_create_caches(util_ldap_state_t *st, const char *url)
-{
- util_url_node_t *curl = NULL;
- util_ald_cache_t *search_cache;
- util_ald_cache_t *compare_cache;
- util_ald_cache_t *dn_compare_cache;
-
- /* create the three caches */
- search_cache = util_ald_create_cache(st->search_cache_size,
- util_ldap_search_node_hash,
- util_ldap_search_node_compare,
- util_ldap_search_node_copy,
- util_ldap_search_node_free);
- compare_cache = util_ald_create_cache(st->compare_cache_size,
- util_ldap_compare_node_hash,
- util_ldap_compare_node_compare,
- util_ldap_compare_node_copy,
- util_ldap_compare_node_free);
- dn_compare_cache = util_ald_create_cache(st->compare_cache_size,
- util_ldap_dn_compare_node_hash,
- util_ldap_dn_compare_node_compare,
- util_ldap_dn_compare_node_copy,
- util_ldap_dn_compare_node_free);
-
- /* check that all the caches initialised successfully */
- if (search_cache && compare_cache && dn_compare_cache) {
-
- curl = (util_url_node_t *)apr_pcalloc(st->pool, sizeof(util_url_node_t));
- curl->url = url;
- curl->search_cache = search_cache;
- curl->compare_cache = compare_cache;
- curl->dn_compare_cache = dn_compare_cache;
-
- util_ald_cache_insert(util_ldap_cache, curl);
-
- }
-
- return curl;
-}
-
-
-util_ald_cache_t *util_ald_create_cache(unsigned long maxentries,
- unsigned long (*hashfunc)(void *),
- int (*comparefunc)(void *, void *),
- void * (*copyfunc)(void *),
- void (*freefunc)(void *))
-{
- util_ald_cache_t *cache;
- int i;
-
- if (maxentries <= 0)
- return NULL;
-
- cache = (util_ald_cache_t *)util_ald_alloc(sizeof(util_ald_cache_t));
- if (!cache)
- return NULL;
-
- cache->maxentries = maxentries;
- cache->numentries = 0;
- cache->size = maxentries / 3;
- if (cache->size < 64) cache->size = 64;
- for (i = 0; primes[i] && primes[i] < cache->size; ++i) ;
- cache->size = primes[i]? primes[i] : primes[i-1];
-
- cache->nodes = (util_cache_node_t **)util_ald_alloc(cache->size * sizeof(util_cache_node_t *));
- if (!cache->nodes) {
- util_ald_free(cache);
- return NULL;
- }
-
- for (i=0; i < cache->size; ++i)
- cache->nodes[i] = NULL;
-
- cache->hash = hashfunc;
- cache->compare = comparefunc;
- cache->copy = copyfunc;
- cache->free = freefunc;
-
- cache->fullmark = cache->maxentries / 4 * 3;
- cache->marktime = 0;
- cache->avg_purgetime = 0.0;
- cache->numpurges = 0;
- cache->last_purge = 0;
- cache->npurged = 0;
-
- cache->fetches = 0;
- cache->hits = 0;
- cache->inserts = 0;
- cache->removes = 0;
-
- return cache;
-}
-
-void util_ald_destroy_cache(util_ald_cache_t *cache)
-{
- int i;
- util_cache_node_t *p, *q;
-
- if (cache == NULL)
- return;
-
- for (i = 0; i < cache->size; ++i) {
- p = cache->nodes[i];
- q = NULL;
- while (p != NULL) {
- q = p->next;
- (*cache->free)(p->payload);
- util_ald_free(p);
- p = q;
- }
- }
- util_ald_free(cache->nodes);
-}
-
-void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload)
-{
- int hashval;
- util_cache_node_t *p;
-
- if (cache == NULL)
- return NULL;
-
- cache->fetches++;
-
- hashval = (*cache->hash)(payload) % cache->size;
- for (p = cache->nodes[hashval];
- p && !(*cache->compare)(p->payload, payload);
- p = p->next) ;
-
- if (p != NULL) {
- cache->hits++;
- return p->payload;
- }
- else {
- return NULL;
- }
-}
-
-/*
- * Insert an item into the cache.
- * *** Does not catch duplicates!!! ***
- */
-void util_ald_cache_insert(util_ald_cache_t *cache, void *payload)
-{
- int hashval;
- util_cache_node_t *node;
-
- if (cache == NULL || payload == NULL)
- return;
-
- cache->inserts++;
- hashval = (*cache->hash)(payload) % cache->size;
- node = (util_cache_node_t *)util_ald_alloc(sizeof(util_cache_node_t));
- node->add_time = apr_time_now();
- node->payload = (*cache->copy)(payload);
- node->next = cache->nodes[hashval];
- cache->nodes[hashval] = node;
- if (++cache->numentries == cache->fullmark)
- cache->marktime=apr_time_now();
- if (cache->numentries >= cache->maxentries)
- util_ald_cache_purge(cache);
-}
-
-void util_ald_cache_remove(util_ald_cache_t *cache, void *payload)
-{
- int hashval;
- util_cache_node_t *p, *q;
-
- if (cache == NULL)
- return;
-
- cache->removes++;
- hashval = (*cache->hash)(payload) % cache->size;
- for (p = cache->nodes[hashval], q=NULL;
- p && !(*cache->compare)(p->payload, payload);
- p = p->next) {
- q = p;
- }
-
- /* If p is null, it means that we couldn't find the node, so just return */
- if (p == NULL)
- return;
-
- if (q == NULL) {
- /* We found the node, and it's the first in the list */
- cache->nodes[hashval] = p->next;
- }
- else {
- /* We found the node and it's not the first in the list */
- q->next = p->next;
- }
- (*cache->free)(p->payload);
- util_ald_free(p);
- cache->numentries--;
-}
-
-char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char *name)
-{
- int i;
- int totchainlen = 0;
- int nchains = 0;
- double chainlen;
- util_cache_node_t *n;
- char *buf;
-
- if (cache == NULL) {
- return "";
- }
-
- for (i=0; i < cache->size; ++i) {
- if (cache->nodes[i] != NULL) {
- nchains++;
- for (n = cache->nodes[i]; n != NULL; n = n->next)
- totchainlen++;
- }
- }
- chainlen = nchains? (double)totchainlen / (double)nchains : 0;
-
- buf = apr_psprintf(p,
- "<tr valign='top'>"
- "<td nowrap>%s</td>"
- "<td align='right' nowrap>%lu (%.0f%% full)</td>"
- "<td align='right'>%.1f</td>"
- "<td align='right'>%lu/%lu</td>"
- "<td align='right'>%.0f%%</td>"
- "<td align='right'>%lu/%lu</td>",
- name,
- cache->numentries,
- (double)cache->numentries / (double)cache->maxentries * 100.0,
- chainlen,
- cache->hits,
- cache->fetches,
- (cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0),
- cache->inserts,
- cache->removes);
-
- if (cache->numpurges) {
- char str_ctime[APR_CTIME_LEN];
-
- apr_ctime(str_ctime, cache->last_purge);
- buf = apr_psprintf(p,
- "%s"
- "<td align='right'>%lu</td>\n"
- "<td align='right' nowrap>%s</td>\n",
- buf,
- cache->numpurges,
- str_ctime);
- }
- else {
- buf = apr_psprintf(p,
- "%s<td colspan='2' align='center'>(none)</td>\n",
- buf);
- }
-
- buf = apr_psprintf(p, "%s<td align='right'>%.2g</td>\n</tr>", buf, cache->avg_purgetime);
-
- return buf;
-}
-
-char *util_ald_cache_display(apr_pool_t *pool)
-{
- int i;
- char *buf, *t1, *t2, *t3;
-
- if (!util_ldap_cache) {
- return "<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>";
- }
-
- buf = util_ald_cache_display_stats(pool, util_ldap_cache, "LDAP URL Cache");
-
- for (i=0; i < util_ldap_cache->size; ++i) {
- util_cache_node_t *p;
- for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
- util_url_node_t *n;
-
- n = (util_url_node_t *)p->payload;
-
- t1 = apr_psprintf(pool, "%s (Searches)", n->url);
- t2 = apr_psprintf(pool, "%s (Compares)", n->url);
- t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
-
- buf = apr_psprintf(pool, "%s\n\n"
- "%s\n\n"
- "%s\n\n"
- "%s\n\n",
- buf,
- util_ald_cache_display_stats(pool, n->search_cache, t1),
- util_ald_cache_display_stats(pool, n->compare_cache, t2),
- util_ald_cache_display_stats(pool, n->dn_compare_cache, t3)
- );
- }
- }
- return buf;
-}
-
-#endif /* APU_HAS_LDAP */