diff options
Diffstat (limited to 'modules/experimental')
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><routine-name>", r); - ap_rputs("(<routine-data>)</SAMP>\n", r); - ap_rputs(" </DT>\n", r); - ap_rputs(" <DD><SAMP>[<applies-to>]</SAMP>\n", r); - ap_rputs(" </DD>\n", r); - ap_rputs(" </DL>\n", r); - ap_rputs(" <P>\n", r); - ap_rputs(" The <SAMP><routine-data></SAMP> is supplied by\n", r); - ap_rputs(" the routine when it requests the trace,\n", r); - ap_rputs(" and the <SAMP><applies-to></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 */ |