summaryrefslogtreecommitdiff
path: root/modules/experimental
diff options
context:
space:
mode:
authorNick Kew <niq@apache.org>2005-09-21 09:46:12 +0000
committerNick Kew <niq@apache.org>2005-09-21 09:46:12 +0000
commitd2fa38ef90889787647a70232bf45e4ac4e694bd (patch)
treeaf96e29da10c04e0d16e8341aae4457a423bdca7 /modules/experimental
parent31bebda15a61723fdb9f8f002263653be2f92ba6 (diff)
downloadhttpd-d2fa38ef90889787647a70232bf45e4ac4e694bd.tar.gz
Move mod_filter and mod_charset_lite from /experimental/ to /filters/
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@290669 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/experimental')
-rw-r--r--modules/experimental/NWGNUcharsetl260
-rw-r--r--modules/experimental/NWGNUmakefile2
-rw-r--r--modules/experimental/NWGNUmod_filter250
-rw-r--r--modules/experimental/config.m412
-rw-r--r--modules/experimental/mod_charset_lite.c1138
-rw-r--r--modules/experimental/mod_charset_lite.dsp124
-rw-r--r--modules/experimental/mod_charset_lite.exp1
-rw-r--r--modules/experimental/mod_filter.c850
8 files changed, 6 insertions, 2631 deletions
diff --git a/modules/experimental/NWGNUcharsetl b/modules/experimental/NWGNUcharsetl
deleted file mode 100644
index 7094e9447f..0000000000
--- a/modules/experimental/NWGNUcharsetl
+++ /dev/null
@@ -1,260 +0,0 @@
-#
-# Declare the sub-directories to be built here
-#
-
-SUBDIRS = \
- $(EOLIST)
-
-#
-# Get the 'head' of the build environment. This includes default targets and
-# paths to tools
-#
-
-include $(AP_WORK)\build\NWGNUhead.inc
-
-#
-# build this level's files
-
-#
-# Make sure all needed macro's are defined
-#
-
-#
-# These directories will be at the beginning of the include list, followed by
-# INCDIRS
-#
-XINCDIRS += \
- $(AP_WORK)/include \
- $(NWOS) \
- $(AP_WORK)/modules/arch/netware \
- $(APR)/include \
- $(APRUTIL)/include \
- $(APR) \
- $(EOLIST)
-
-#
-# These flags will come after CFLAGS
-#
-XCFLAGS += \
- $(EOLIST)
-
-#
-# These defines will come after DEFINES
-#
-XDEFINES += \
- -DAP_WANT_DIR_TRANSLATION \
- $(EOLIST)
-
-#
-# These flags will be added to the link.opt file
-#
-XLFLAGS += \
- $(EOLIST)
-
-#
-# These values will be appended to the correct variables based on the value of
-# RELEASE
-#
-ifeq "$(RELEASE)" "debug"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-ifeq "$(RELEASE)" "noopt"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-ifeq "$(RELEASE)" "release"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-#
-# These are used by the link target if an NLM is being generated
-# This is used by the link 'name' directive to name the nlm. If left blank
-# TARGET_nlm (see below) will be used.
-#
-NLM_NAME = charsetl
-
-#
-# This is used by the link '-desc ' directive.
-# If left blank, NLM_NAME will be used.
-#
-NLM_DESCRIPTION = Apache $(VERSION_STR) Charset Lite Module
-
-#
-# This is used by the '-threadname' directive. If left blank,
-# NLM_NAME Thread will be used.
-#
-NLM_THREAD_NAME = charsetl
-
-#
-# If this is specified, it will override VERSION value in
-# $(AP_WORK)\build\NWGNUenvironment.inc
-#
-NLM_VERSION =
-
-#
-# If this is specified, it will override the default of 64K
-#
-NLM_STACK_SIZE = 8192
-
-
-#
-# If this is specified it will be used by the link '-entry' directive
-#
-NLM_ENTRY_SYM = _LibCPrelude
-
-#
-# If this is specified it will be used by the link '-exit' directive
-#
-NLM_EXIT_SYM = _LibCPostlude
-
-#
-# If this is specified it will be used by the link '-check' directive
-#
-NLM_CHECK_SYM =
-
-#
-# If these are specified it will be used by the link '-flags' directive
-#
-NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
-
-#
-# If this is specified it will be linked in with the XDCData option in the def
-# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
-# by setting APACHE_UNIPROC in the environment
-#
-XDCDATA =
-
-#
-# If there is an NLM target, put it here
-#
-TARGET_nlm = \
- $(OBJDIR)/charsetl.nlm \
- $(EOLIST)
-
-#
-# If there is an LIB target, put it here
-#
-TARGET_lib = \
- $(EOLIST)
-
-#
-# These are the OBJ files needed to create the NLM target above.
-# Paths must all use the '/' character
-#
-FILES_nlm_objs = \
- $(OBJDIR)/mod_charset_lite.o \
- $(EOLIST)
-
-#
-# These are the LIB files needed to create the NLM target above.
-# These will be added as a library command in the link.opt file.
-#
-FILES_nlm_libs = \
- libcpre.o \
- $(EOLIST)
-
-#
-# These are the modules that the above NLM target depends on to load.
-# These will be added as a module command in the link.opt file.
-#
-FILES_nlm_modules = \
- aprlib \
- libc \
- $(EOLIST)
-
-#
-# If the nlm has a msg file, put it's path here
-#
-FILE_nlm_msg =
-
-#
-# If the nlm has a hlp file put it's path here
-#
-FILE_nlm_hlp =
-
-#
-# If this is specified, it will override $(NWOS)\copyright.txt.
-#
-FILE_nlm_copyright =
-
-#
-# Any additional imports go here
-#
-FILES_nlm_Ximports = \
- @$(APR)/aprlib.imp \
- @$(NWOS)/httpd.imp \
- @libc.imp \
- $(EOLIST)
-
-#
-# Any symbols exported to here
-#
-FILES_nlm_exports = \
- charset_lite_module \
- $(EOLIST)
-
-#
-# These are the OBJ files needed to create the LIB target above.
-# Paths must all use the '/' character
-#
-FILES_lib_objs = \
- $(EOLIST)
-
-#
-# implement targets and dependancies (leave this section alone)
-#
-
-libs :: $(OBJDIR) $(TARGET_lib)
-
-nlms :: libs $(TARGET_nlm)
-
-#
-# Updated this target to create necessary directories and copy files to the
-# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
-#
-install :: nlms FORCE
-
-#
-# Any specialized rules here
-#
-
-#
-# Include the 'tail' makefile that has targets that depend on variables defined
-# in this makefile
-#
-
-include $(AP_WORK)\build\NWGNUtail.inc
-
-
-
diff --git a/modules/experimental/NWGNUmakefile b/modules/experimental/NWGNUmakefile
index d6e1337a29..78e453e990 100644
--- a/modules/experimental/NWGNUmakefile
+++ b/modules/experimental/NWGNUmakefile
@@ -152,9 +152,7 @@ XDCDATA =
# If there is an NLM target, put it here
#
TARGET_nlm = \
- $(OBJDIR)/charsetl.nlm \
$(OBJDIR)/example.nlm \
- $(OBJDIR)/mod_filter.nlm \
$(EOLIST)
#
diff --git a/modules/experimental/NWGNUmod_filter b/modules/experimental/NWGNUmod_filter
deleted file mode 100644
index ec671c5963..0000000000
--- a/modules/experimental/NWGNUmod_filter
+++ /dev/null
@@ -1,250 +0,0 @@
-#
-# Make sure all needed macro's are defined
-#
-
-#
-# Get the 'head' of the build environment if necessary. This includes default
-# targets and paths to tools
-#
-
-ifndef EnvironmentDefined
-include $(AP_WORK)\build\NWGNUhead.inc
-endif
-
-#
-# These directories will be at the beginning of the include list, followed by
-# INCDIRS
-#
-XINCDIRS += \
- $(AP_WORK)/include \
- $(NWOS) \
- $(AP_WORK)/modules/arch/netware \
- $(APR)/include \
- $(APRUTIL)/include \
- $(APR) \
- $(EOLIST)
-
-#
-# These flags will come after CFLAGS
-#
-XCFLAGS += \
- -prefix pre_nw.h \
- $(EOLIST)
-
-#
-# These defines will come after DEFINES
-#
-XDEFINES += \
- $(EOLIST)
-
-#
-# These flags will be added to the link.opt file
-#
-XLFLAGS += \
- $(EOLIST)
-
-#
-# These values will be appended to the correct variables based on the value of
-# RELEASE
-#
-ifeq "$(RELEASE)" "debug"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-ifeq "$(RELEASE)" "noopt"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-ifeq "$(RELEASE)" "release"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-#
-# These are used by the link target if an NLM is being generated
-# This is used by the link 'name' directive to name the nlm. If left blank
-# TARGET_nlm (see below) will be used.
-#
-NLM_NAME = mod_filter
-
-#
-# This is used by the link '-desc ' directive.
-# If left blank, NLM_NAME will be used.
-#
-NLM_DESCRIPTION = Apache $(VERSION_STR) Filter Module
-
-#
-# This is used by the '-threadname' directive. If left blank,
-# NLM_NAME Thread will be used.
-#
-NLM_THREAD_NAME = Filter Module
-
-#
-# If this is specified, it will override VERSION value in
-# $(AP_WORK)\build\NWGNUenvironment.inc
-#
-NLM_VERSION =
-
-#
-# If this is specified, it will override the default of 64K
-#
-NLM_STACK_SIZE = 8192
-
-
-#
-# If this is specified it will be used by the link '-entry' directive
-#
-NLM_ENTRY_SYM = _LibCPrelude
-
-#
-# If this is specified it will be used by the link '-exit' directive
-#
-NLM_EXIT_SYM = _LibCPostlude
-
-#
-# If this is specified it will be used by the link '-check' directive
-#
-NLM_CHECK_SYM =
-
-#
-# If these are specified it will be used by the link '-flags' directive
-#
-NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
-
-#
-# If this is specified it will be linked in with the XDCData option in the def
-# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
-# by setting APACHE_UNIPROC in the environment
-#
-XDCDATA =
-
-#
-# If there is an NLM target, put it here
-#
-TARGET_nlm = \
- $(OBJDIR)/mod_filter.nlm \
- $(EOLIST)
-
-#
-# If there is an LIB target, put it here
-#
-TARGET_lib = \
- $(EOLIST)
-
-#
-# These are the OBJ files needed to create the NLM target above.
-# Paths must all use the '/' character
-#
-FILES_nlm_objs = \
- $(OBJDIR)/mod_filter.o \
- $(EOLIST)
-
-#
-# These are the LIB files needed to create the NLM target above.
-# These will be added as a library command in the link.opt file.
-#
-FILES_nlm_libs = \
- libcpre.o \
- $(EOLIST)
-
-#
-# These are the modules that the above NLM target depends on to load.
-# These will be added as a module command in the link.opt file.
-#
-FILES_nlm_modules = \
- aprlib \
- libc \
- $(EOLIST)
-
-#
-# If the nlm has a msg file, put it's path here
-#
-FILE_nlm_msg =
-
-#
-# If the nlm has a hlp file put it's path here
-#
-FILE_nlm_hlp =
-
-#
-# If this is specified, it will override $(NWOS)\copyright.txt.
-#
-FILE_nlm_copyright =
-
-#
-# Any additional imports go here
-#
-FILES_nlm_Ximports = \
- @$(APR)/aprlib.imp \
- @$(NWOS)/httpd.imp \
- @libc.imp \
- $(EOLIST)
-
-#
-# Any symbols exported to here
-#
-FILES_nlm_exports = \
- filter_module \
- $(EOLIST)
-
-#
-# These are the OBJ files needed to create the LIB target above.
-# Paths must all use the '/' character
-#
-FILES_lib_objs = \
- $(EOLIST)
-
-#
-# implement targets and dependancies (leave this section alone)
-#
-
-libs :: $(OBJDIR) $(TARGET_lib)
-
-nlms :: libs $(TARGET_nlm)
-
-#
-# Updated this target to create necessary directories and copy files to the
-# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
-#
-install :: nlms FORCE
-
-#
-# Any specialized rules here
-#
-
-#
-# Include the 'tail' makefile that has targets that depend on variables defined
-# in this makefile
-#
-
-include $(AP_WORK)\build\NWGNUtail.inc
-
diff --git a/modules/experimental/config.m4 b/modules/experimental/config.m4
index c1a91e646b..07cab54e05 100644
--- a/modules/experimental/config.m4
+++ b/modules/experimental/config.m4
@@ -1,18 +1,18 @@
APACHE_MODPATH_INIT(experimental)
-if test "$ac_cv_ebcdic" = "yes"; then
+#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
+# APACHE_MODULE(charset_lite, character set translation, , , yes)
+#else
+# APACHE_MODULE(charset_lite, character set translation, , , no)
+#fi
APACHE_MODULE(example, example and demo module, , , no)
APACHE_MODULE(case_filter, example uppercase conversion filter, , , no)
APACHE_MODULE(case_filter_in, example uppercase conversion input filter, , , no)
-APACHE_MODULE(filter, smart filtering module, , , no)
+#APACHE_MODULE(filter, smart filtering module, , , no)
APACHE_MODULE(dbd, Apache DBD Framework, , , no)
APACHE_MODPATH_FINISH
diff --git a/modules/experimental/mod_charset_lite.c b/modules/experimental/mod_charset_lite.c
deleted file mode 100644
index 66b8ef0793..0000000000
--- a/modules/experimental/mod_charset_lite.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
- * applicable.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * 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, 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, 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 || AP_WANT_DIR_TRANSLATION
- /* 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, 0, r,
- "mime type is %s; no translation selected",
- mime_type);
- }
- /* We must not bail out here (i.e., the MIME test must be in the filter
- * itself, not in the fixup, because only then is the final MIME type known.
- * Examples for late changes to the MIME type include CGI handling (MIME
- * type is set in the Content-Type header produced by the CGI script), or
- * PHP (until PHP runs, the MIME type is set to application/x-httpd-php)
- */
- }
-
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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;
-
- /* We must not open the xlation table here yet, because the final MIME
- * type is not known until we are actually called in the output filter.
- * With POST or PUT request, the case is different, because their MIME
- * type is set in the request headers, and their data are prerequisites
- * for actually calling, e.g., the CGI handler later on.
- */
- output_ctx->xlate = NULL;
-
- 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,
- r->connection->bucket_alloc);
- 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, 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, 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)
-{
- request_rec *r = f->r;
- conn_rec *c = r->connection;
- apr_bucket_brigade *bb;
- apr_bucket *b;
- charset_filter_ctx_t *ctx = f->ctx;
- apr_status_t rv;
-
- bb = apr_brigade_create(r->pool, c->bucket_alloc);
- b = apr_bucket_transient_create(tmp, len, c->bucket_alloc);
- 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)
-{
- request_rec *r = f->r;
- conn_rec *c = r->connection;
- apr_bucket_brigade *bb;
- apr_bucket *b;
- charset_filter_ctx_t *ctx = f->ctx;
- apr_status_t rv;
-
- bb = apr_brigade_create(r->pool, c->bucket_alloc);
- b = apr_bucket_eos_create(c->bucket_alloc);
- 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;
-
- switch(ctx->ees) {
- case EES_LIMIT:
- rv = 0;
- msg = "xlate filter - a built-in restriction was encountered";
- break;
- case EES_BAD_INPUT:
- rv = 0;
- msg = "xlate filter - an input character was invalid";
- break;
- case EES_BUCKET_READ:
- rv = 0;
- msg = "xlate filter - bucket read routine failed";
- break;
- case EES_INCOMPLETE_CHAR:
- rv = 0;
- strcpy(msgbuf, "xlate filter - incomplete char at end of input - ");
- cur = 0;
- while ((apr_size_t)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, APLOG_ERR, 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,
- 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,
- 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;
- }
- }
-
- /* catch proxy requests */
- if (f->r->proxyreq) return DECLINED;
-
- /* Opening the output translation (this used to be done in the fixup hook,
- * but that was too early: a subsequent type modification, e.g., by a
- * CGI script, would go unnoticed. Now we do it in the filter itself.)
- */
- if (!ctx->noop && ctx->xlate == NULL)
- {
- const char *mime_type = f->r->content_type ? f->r->content_type : ap_default_type(f->r);
-
- /* 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) == 0 ||
-#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) == 0 ||
-#endif
- strncasecmp(mime_type, "message/", 8) == 0) {
-
- rv = apr_xlate_open(&ctx->xlate,
- dc->charset_default, dc->charset_source, f->r->pool);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "can't open translation %s->%s",
- dc->charset_source, dc->charset_default);
- ctx->noop = 1;
- }
- }
- else {
- ctx->noop = 1;
- if (dc->debug >= DBGLVL_GORY)
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r,
- "mime type is %s; no translation selected",
- mime_type);
- }
- }
-
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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, 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,
- NULL, f->r->connection->bucket_alloc);
- /* 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, NULL,
- AP_FTYPE_RESOURCE);
- ap_register_input_filter(XLATEIN_FILTER_NAME, xlate_in_filter, NULL,
- 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.dsp b/modules/experimental/mod_charset_lite.dsp
deleted file mode 100644
index de3707707a..0000000000
--- a/modules/experimental/mod_charset_lite.dsp
+++ /dev/null
@@ -1,124 +0,0 @@
-# Microsoft Developer Studio Project File - Name="mod_charset_lite" - 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_charset_lite - 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_charset_lite.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_charset_lite.mak" CFG="mod_charset_lite - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_charset_lite - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_charset_lite - 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_charset_lite - 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 /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
-# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_charset_lite_src" /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 /nologo /subsystem:windows /dll /machine:I386
-# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Release/mod_charset_lite.so" /base:@..\..\os\win32\BaseAddr.ref,mod_charset_lite.so /opt:ref
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - 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 /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
-# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_charset_lite_src" /FD /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 /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386
-# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_charset_lite.so" /base:@..\..\os\win32\BaseAddr.ref,mod_charset_lite.so
-
-!ENDIF
-
-# Begin Target
-
-# Name "mod_charset_lite - Win32 Release"
-# Name "mod_charset_lite - Win32 Debug"
-# Begin Source File
-
-SOURCE=.\mod_charset_lite.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\build\win32\win32ver.awk
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release"
-
-# PROP Ignore_Default_Tool 1
-# Begin Custom Build - Creating Version Resource
-InputPath=..\..\build\win32\win32ver.awk
-
-".\mod_charset_lite.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- awk -f ../../build/win32/win32ver.awk mod_charset_lite.so "charset_lite_module for Apache" ../../include/ap_release.h > .\mod_charset_lite.rc
-
-# End Custom Build
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-# PROP Ignore_Default_Tool 1
-# Begin Custom Build - Creating Version Resource
-InputPath=..\..\build\win32\win32ver.awk
-
-".\mod_charset_lite.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- awk -f ../../build/win32/win32ver.awk mod_charset_lite.so "charset_lite_module for Apache" ../../include/ap_release.h > .\mod_charset_lite.rc
-
-# End Custom Build
-
-!ENDIF
-
-# End Source File
-# End Target
-# End Project
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_filter.c b/modules/experimental/mod_filter.c
deleted file mode 100644
index d0687f4030..0000000000
--- a/modules/experimental/mod_filter.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/* Copyright 2004-2005 The Apache Software Foundation or its licensors, as
- * applicable.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Originally contributed by Nick Kew <nick webthing.com>
- *
- * At the time of writing, this is designed primarily for use with
- * httpd 2.2, but is also back-compatible with 2.0. It is likely
- * that the 2.0 and 2.2 versions may diverge in future, as additional
- * capabilities for 2.2 are added, including updates to util_filter.
- *
- * 21/9/04: Unifying data structures with util_filter.
- * From now on, until and unless we backport, mod_filter requires
- * util_filter.h from CVS or httpd-2.1+ to compile.
- * There's a minimal patch for httpd-2.0 users maintained by Nick
- * to compile mod_filter at http://www.apache.org/~niq/
- */
-
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-#include "apr_lib.h"
-#include "apr_strings.h"
-#include "apr_hash.h"
-#include "httpd.h"
-#include "http_config.h"
-#include "http_request.h"
-#include "http_log.h"
-#include "util_filter.h"
-
-module AP_MODULE_DECLARE_DATA filter_module;
-
-/**
- * @brief is a filter provider, as defined and implemented by mod_filter.
- *
- * The struct is a linked list, with dispatch criteria
- * defined for each filter. The provider implementation itself is a
- * (2.0-compatible) ap_filter_rec_t* frec.
- */
-struct ap_filter_provider_t {
- /** How to match this provider to filter dispatch criterion */
- enum {
- STRING_MATCH,
- STRING_CONTAINS,
- REGEX_MATCH,
- INT_EQ,
- INT_LT,
- INT_LE,
- INT_GT,
- INT_GE,
- DEFINED
- } match_type;
-
- /** negation on match_type */
- int not;
-
- /** The dispatch match itself - union member depends on match_type */
- union {
- const char *string;
- ap_regex_t *regex;
- int number;
- } match;
-
- /** The filter that implements this provider */
- ap_filter_rec_t *frec;
-
- /** The next provider in the list */
- ap_filter_provider_t *next;
-
- /** Dispatch criteria for filter providers */
- enum {
- HANDLER,
- REQUEST_HEADERS,
- RESPONSE_HEADERS,
- SUBPROCESS_ENV,
- CONTENT_TYPE
- } dispatch;
-
- /** Match value for filter providers */
- const char* value;
-};
-
-/** we need provider_ctx to save ctx values set by providers in filter_init */
-typedef struct provider_ctx provider_ctx;
-struct provider_ctx {
- ap_filter_provider_t *provider;
- void *ctx;
- provider_ctx *next;
-};
-typedef struct {
- ap_out_filter_func func;
- void *fctx;
- provider_ctx *init_ctx;
-} harness_ctx;
-
-typedef struct mod_filter_chain {
- const char *fname;
- struct mod_filter_chain *next;
-} mod_filter_chain;
-
-typedef struct {
- apr_hash_t *live_filters;
- mod_filter_chain *chain;
-} mod_filter_cfg;
-
-typedef struct {
- const char* range ;
-} mod_filter_ctx ;
-
-
-static void filter_trace(conn_rec *c, int debug, const char *fname,
- apr_bucket_brigade *bb)
-{
- apr_bucket *b;
-
- switch (debug) {
- case 0: /* normal, operational use */
- return;
- case 1: /* mod_diagnostics level */
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s", fname);
- for (b = APR_BRIGADE_FIRST(bb);
- b != APR_BRIGADE_SENTINEL(bb);
- b = APR_BUCKET_NEXT(b)) {
-
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
- "%s: type: %s, length: %" APR_SIZE_T_FMT,
- fname, b->type->name ? b->type->name : "(unknown)",
- b->length);
- }
- break;
- }
-}
-
-static int filter_init(ap_filter_t *f)
-{
- ap_filter_provider_t *p;
- provider_ctx *pctx;
- int err;
- ap_filter_rec_t *filter = f->frec;
-
- harness_ctx *fctx = apr_pcalloc(f->r->pool, sizeof(harness_ctx));
- for (p = filter->providers; p; p = p->next) {
- if (p->frec->filter_init_func) {
- f->ctx = NULL;
- if ((err = p->frec->filter_init_func(f)) != OK) {
- ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c,
- "filter_init for %s failed", p->frec->name);
- return err; /* if anyone errors out here, so do we */
- }
- if (f->ctx != NULL) {
- /* the filter init function set a ctx - we need to record it */
- pctx = apr_pcalloc(f->r->pool, sizeof(provider_ctx));
- pctx->provider = p;
- pctx->ctx = f->ctx;
- pctx->next = fctx->init_ctx;
- fctx->init_ctx = pctx;
- }
- }
- }
- f->ctx = fctx;
- return OK;
-}
-
-static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
-{
- ap_filter_provider_t *provider;
- const char *str = NULL;
- char *str1;
- int match;
- unsigned int proto_flags;
- request_rec *r = f->r;
- harness_ctx *ctx = f->ctx;
- provider_ctx *pctx;
- mod_filter_ctx *rctx = ap_get_module_config(r->request_config,
- &filter_module);
-
- /* Check registered providers in order */
- for (provider = filter->providers; provider; provider = provider->next) {
- match = 1;
- switch (provider->dispatch) {
- case REQUEST_HEADERS:
- str = apr_table_get(r->headers_in, provider->value);
- break;
- case RESPONSE_HEADERS:
- str = apr_table_get(r->headers_out, provider->value);
- break;
- case SUBPROCESS_ENV:
- str = apr_table_get(r->subprocess_env, provider->value);
- break;
- case CONTENT_TYPE:
- str = r->content_type;
- break;
- case HANDLER:
- str = r->handler;
- break;
- }
-
- /* treat nulls so we don't have to check every strcmp individually
- * Not sure if there's anything better to do with them
- */
- if (!str) {
- if (provider->match_type == DEFINED && provider->match.string) {
- match = 0;
- }
- }
- else if (!provider->match.string) {
- match = 0;
- }
- else {
- /* Now we have no nulls, so we can do string and regexp matching */
- switch (provider->match_type) {
- case STRING_MATCH:
- if (strcasecmp(str, provider->match.string)) {
- match = 0;
- }
- break;
- case STRING_CONTAINS:
- str1 = apr_pstrdup(r->pool, str);
- ap_str_tolower(str1);
- if (!strstr(str1, provider->match.string)) {
- match = 0;
- }
- break;
- case REGEX_MATCH:
- if (ap_regexec(provider->match.regex, str, 0, NULL, 0)
- == AP_REG_NOMATCH) {
- match = 0;
- }
- break;
- case INT_EQ:
- if (atoi(str) != provider->match.number) {
- match = 0;
- }
- break;
- case INT_LT:
- if (atoi(str) < provider->match.number) {
- match = 0;
- }
- break;
- case INT_LE:
- if (atoi(str) <= provider->match.number) {
- match = 0;
- }
- break;
- case INT_GT:
- if (atoi(str) > provider->match.number) {
- match = 0;
- }
- break;
- case INT_GE:
- if (atoi(str) >= provider->match.number) {
- match = 0;
- }
- break;
- case DEFINED: /* we already handled this:-) */
- break;
- }
- }
-
- if (match != provider->not) {
- /* condition matches this provider */
-#ifndef NO_PROTOCOL
- /* check protocol
- *
- * FIXME:
- * This is a quick hack and almost certainly buggy.
- * The idea is that by putting this in mod_filter, we relieve
- * filter implementations of the burden of fixing up HTTP headers
- * for cases that are routinely affected by filters.
- *
- * Default is ALWAYS to do nothing, so as not to tread on the
- * toes of filters which want to do it themselves.
- *
- */
- proto_flags = provider->frec->proto_flags;
-
- /* some specific things can't happen in a proxy */
- if (r->proxyreq) {
- if (proto_flags & AP_FILTER_PROTO_NO_PROXY) {
- /* can't use this provider; try next */
- continue;
- }
-
- if (proto_flags & AP_FILTER_PROTO_TRANSFORM) {
- str = apr_table_get(r->headers_out, "Cache-Control");
- if (str) {
- str1 = apr_pstrdup(r->pool, str);
- ap_str_tolower(str1);
- if (strstr(str1, "no-transform")) {
- /* can't use this provider; try next */
- continue;
- }
- }
- apr_table_addn(r->headers_out, "Warning",
- apr_psprintf(r->pool,
- "214 %s Transformation applied",
- r->hostname));
- }
- }
-
- /* things that are invalidated if the filter transforms content */
- if (proto_flags & AP_FILTER_PROTO_CHANGE) {
- apr_table_unset(r->headers_out, "Content-MD5");
- apr_table_unset(r->headers_out, "ETag");
- if (proto_flags & AP_FILTER_PROTO_CHANGE_LENGTH) {
- apr_table_unset(r->headers_out, "Content-Length");
- }
- }
-
- /* no-cache is for a filter that has different effect per-hit */
- if (proto_flags & AP_FILTER_PROTO_NO_CACHE) {
- apr_table_unset(r->headers_out, "Last-Modified");
- apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
- }
-
- if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) {
- apr_table_unset(r->headers_out, "Accept-Ranges");
- }
- else if (rctx && rctx->range) {
- /* restore range header we saved earlier */
- apr_table_setn(r->headers_in, "Range", rctx->range);
- rctx->range = NULL;
- }
-#endif
- for (pctx = ctx->init_ctx; pctx; pctx = pctx->next) {
- if (pctx->provider == provider) {
- ctx->fctx = pctx->ctx ;
- }
- }
- ctx->func = provider->frec->filter_func.out_func;
- return 1;
- }
- }
-
- /* No provider matched */
- return 0;
-}
-
-static apr_status_t filter_harness(ap_filter_t *f, apr_bucket_brigade *bb)
-{
- apr_status_t ret;
- const char *cachecontrol;
- char *str;
- harness_ctx *ctx = f->ctx;
- ap_filter_rec_t *filter = f->frec;
-
- if (f->r->status != 200) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
-
- filter_trace(f->c, filter->debug, f->frec->name, bb);
-
- /* look up a handler function if we haven't already set it */
- if (!ctx->func) {
-#ifndef NO_PROTOCOL
- if (f->r->proxyreq) {
- if (filter->proto_flags & AP_FILTER_PROTO_NO_PROXY) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
-
- if (filter->proto_flags & AP_FILTER_PROTO_TRANSFORM) {
- cachecontrol = apr_table_get(f->r->headers_out,
- "Cache-Control");
- if (cachecontrol) {
- str = apr_pstrdup(f->r->pool, cachecontrol);
- ap_str_tolower(str);
- if (strstr(str, "no-transform")) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
- }
- }
- }
-#endif
- if (!filter_lookup(f, filter)) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
- }
-
- /* call the content filter with its own context, then restore our
- * context
- */
- f->ctx = ctx->fctx;
- ret = ctx->func(f, bb);
- ctx->fctx = f->ctx;
- f->ctx = ctx;
-
- return ret;
-}
-
-#ifndef NO_PROTOCOL
-static const char *filter_protocol(cmd_parms *cmd, void *CFG, const char *fname,
- const char *pname, const char *proto)
-{
- static const char *sep = ";, \t";
- char *arg;
- char *tok = 0;
- unsigned int flags = 0;
- mod_filter_cfg *cfg = CFG;
- ap_filter_provider_t *provider = NULL;
- ap_filter_rec_t *filter = apr_hash_get(cfg->live_filters, fname,
- APR_HASH_KEY_STRING);
-
- if (!filter) {
- return "FilterProtocol: No such filter";
- }
-
- /* Fixup the args: it's really pname that's optional */
- if (proto == NULL) {
- proto = pname;
- pname = NULL;
- }
- else {
- /* Find provider */
- for (provider = filter->providers; provider; provider = provider->next){
- if (!strcasecmp(provider->frec->name, pname)) {
- break;
- }
- }
- if (!provider) {
- return "FilterProtocol: No such provider for this filter";
- }
- }
-
- /* Now set flags from our args */
- for (arg = apr_strtok(apr_pstrdup(cmd->pool, proto), sep, &tok);
- arg; arg = apr_strtok(NULL, sep, &tok)) {
-
- if (!strcasecmp(arg, "change=yes")) {
- flags |= AP_FILTER_PROTO_CHANGE | AP_FILTER_PROTO_CHANGE_LENGTH;
- }
- else if (!strcasecmp(arg, "change=1:1")) {
- flags |= AP_FILTER_PROTO_CHANGE;
- }
- else if (!strcasecmp(arg, "byteranges=no")) {
- flags |= AP_FILTER_PROTO_NO_BYTERANGE;
- }
- else if (!strcasecmp(arg, "proxy=no")) {
- flags |= AP_FILTER_PROTO_NO_PROXY;
- }
- else if (!strcasecmp(arg, "proxy=transform")) {
- flags |= AP_FILTER_PROTO_TRANSFORM;
- }
- else if (!strcasecmp(arg, "cache=no")) {
- flags |= AP_FILTER_PROTO_NO_CACHE;
- }
- }
-
- if (pname) {
- provider->frec->proto_flags = flags;
- }
- else {
- filter->proto_flags = flags;
- }
-
- return NULL;
-}
-#endif
-
-static const char *filter_declare(cmd_parms *cmd, void *CFG, const char *fname,
- const char *place)
-{
- mod_filter_cfg *cfg = (mod_filter_cfg *)CFG;
- ap_filter_rec_t *filter;
-
- filter = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t));
- apr_hash_set(cfg->live_filters, fname, APR_HASH_KEY_STRING, filter);
-
- filter->name = fname;
- filter->filter_init_func = filter_init;
- filter->filter_func.out_func = filter_harness;
- filter->ftype = AP_FTYPE_RESOURCE;
- filter->next = NULL;
-
- if (place) {
- if (!strcasecmp(place, "CONTENT_SET")) {
- filter->ftype = AP_FTYPE_CONTENT_SET;
- }
- else if (!strcasecmp(place, "PROTOCOL")) {
- filter->ftype = AP_FTYPE_PROTOCOL;
- }
- else if (!strcasecmp(place, "CONNECTION")) {
- filter->ftype = AP_FTYPE_CONNECTION;
- }
- else if (!strcasecmp(place, "NETWORK")) {
- filter->ftype = AP_FTYPE_NETWORK;
- }
- }
-
- return NULL;
-}
-
-static const char *filter_provider(cmd_parms *cmd, void *CFG, const char *args)
-{
- mod_filter_cfg *cfg = CFG;
- int flags;
- ap_filter_provider_t *provider;
- const char *rxend;
- const char *c;
- char *str;
- const char *eq;
- ap_filter_rec_t* frec;
- ap_filter_rec_t* provider_frec;
-
- /* insist on exactly four arguments */
- const char *fname = ap_getword_conf(cmd->pool, &args) ;
- const char *pname = ap_getword_conf(cmd->pool, &args) ;
- const char *condition = ap_getword_conf(cmd->pool, &args) ;
- const char *match = ap_getword_conf(cmd->pool, &args) ;
- eq = ap_getword_conf(cmd->pool, &args) ;
- if ( !*fname || !*pname || !*match || !*condition || *eq ) {
- return "usage: FilterProvider filter provider condition match" ;
- }
-
- /* fname has been declared with DeclareFilter, so we can look it up */
- frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
-
- /* or if provider is mod_filter itself, we can also look it up */
- if (!frec) {
- c = filter_declare(cmd, CFG, fname, NULL);
- if ( c ) {
- return c;
- }
- frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
- }
-
- if (!frec) {
- return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname);
- }
-
- /* if provider has been registered, we can look it up */
- provider_frec = ap_get_output_filter_handle(pname);
- if (!provider_frec) {
- provider_frec = apr_hash_get(cfg->live_filters, pname,
- APR_HASH_KEY_STRING);
- }
- if (!provider_frec) {
- return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname);
- }
-
- provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t));
- if (*match == '!') {
- provider->not = 1;
- ++match;
- }
- else {
- provider->not = 0;
- }
-
- switch (*match++) {
- case '<':
- if (*match == '=') {
- provider->match_type = INT_LE;
- ++match;
- }
- else {
- provider->match_type = INT_LT;
- }
- provider->match.number = atoi(match);
- break;
- case '>':
- if (*match == '=') {
- provider->match_type = INT_GE;
- ++match;
- }
- else {
- provider->match_type = INT_GT;
- }
- provider->match.number = atoi(match);
- break;
- case '=':
- provider->match_type = INT_EQ;
- provider->match.number = atoi(match);
- break;
- case '/':
- provider->match_type = REGEX_MATCH;
- rxend = ap_strchr_c(match, '/');
- if (!rxend) {
- return "Bad regexp syntax";
- }
- flags = AP_REG_NOSUB; /* we're not mod_rewrite:-) */
- for (c = rxend+1; *c; ++c) {
- switch (*c) {
- case 'i': flags |= AP_REG_ICASE; break;
- }
- }
- provider->match.regex = ap_pregcomp(cmd->pool,
- apr_pstrndup(cmd->pool,
- match,
- rxend-match),
- flags);
- break;
- case '*':
- provider->match_type = DEFINED;
- provider->match.number = -1;
- break;
- case '$':
- provider->match_type = STRING_CONTAINS;
- str = apr_pstrdup(cmd->pool, match);
- ap_str_tolower(str);
- provider->match.string = str;
- break;
- default:
- provider->match_type = STRING_MATCH;
- provider->match.string = apr_pstrdup(cmd->pool, match-1);
- break;
- }
- provider->frec = provider_frec;
- provider->next = frec->providers;
- frec->providers = provider;
-
- /* determine what a filter will dispatch this provider on */
- eq = ap_strchr_c(condition, '=');
- if (eq) {
- str = apr_pstrdup(cmd->pool, eq+1);
- if (!strncasecmp(condition, "env=", 4)) {
- provider->dispatch = SUBPROCESS_ENV;
- }
- else if (!strncasecmp(condition, "req=", 4)) {
- provider->dispatch = REQUEST_HEADERS;
- }
- else if (!strncasecmp(condition, "resp=", 5)) {
- provider->dispatch = RESPONSE_HEADERS;
- }
- else {
- return "FilterProvider: unrecognized dispatch table";
- }
- }
- else {
- if (!strcasecmp(condition, "handler")) {
- provider->dispatch = HANDLER;
- }
- else {
- provider->dispatch = RESPONSE_HEADERS;
- }
- str = apr_pstrdup(cmd->pool, condition);
- ap_str_tolower(str);
- }
-
- if ( (provider->dispatch == RESPONSE_HEADERS)
- && !strcmp(str, "content-type")) {
- provider->dispatch = CONTENT_TYPE;
- }
- provider->value = str;
-
- return NULL;
-}
-
-static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg)
-{
- mod_filter_chain *p;
- mod_filter_chain *q;
- mod_filter_cfg *cfg = CFG;
-
- switch (arg[0]) {
- case '+': /* add to end of chain */
- p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
- p->fname = arg+1;
- if (cfg->chain) {
- for (q = cfg->chain; q->next; q = q->next);
- q->next = p;
- }
- else {
- cfg->chain = p;
- }
- break;
-
- case '@': /* add to start of chain */
- p = apr_palloc(cmd->pool, sizeof(mod_filter_chain));
- p->fname = arg+1;
- p->next = cfg->chain;
- cfg->chain = p;
- break;
-
- case '-': /* remove from chain */
- if (cfg->chain) {
- if (strcasecmp(cfg->chain->fname, arg+1)) {
- for (p = cfg->chain; p->next; p = p->next) {
- if (!strcasecmp(p->next->fname, arg+1)) {
- p->next = p->next->next;
- }
- }
- }
- else {
- cfg->chain = cfg->chain->next;
- }
- }
- break;
-
- case '!': /* Empty the chain */
- cfg->chain = NULL;
- break;
-
- case '=': /* initialise chain with this arg */
- p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
- p->fname = arg+1;
- cfg->chain = p;
- break;
-
- default: /* add to end */
- p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
- p->fname = arg;
- if (cfg->chain) {
- for (q = cfg->chain; q->next; q = q->next);
- q->next = p;
- }
- else {
- cfg->chain = p;
- }
- break;
- }
-
- return NULL;
-}
-
-static const char *filter_debug(cmd_parms *cmd, void *CFG, const char *fname,
- const char *level)
-{
- mod_filter_cfg *cfg = CFG;
- ap_filter_rec_t *frec = apr_hash_get(cfg->live_filters, fname,
- APR_HASH_KEY_STRING);
- if (!frec) {
- return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname);
- }
- frec->debug = atoi(level);
-
- return NULL;
-}
-
-static void filter_insert(request_rec *r)
-{
- mod_filter_chain *p;
- ap_filter_rec_t *filter;
- mod_filter_cfg *cfg = ap_get_module_config(r->per_dir_config,
- &filter_module);
-#ifndef NO_PROTOCOL
- int ranges = 1;
- mod_filter_ctx *ctx = apr_pcalloc(r->pool, sizeof(mod_filter_ctx));
- ap_set_module_config(r->request_config, &filter_module, ctx);
-#endif
-
- for (p = cfg->chain; p; p = p->next) {
- filter = apr_hash_get(cfg->live_filters, p->fname, APR_HASH_KEY_STRING);
- ap_add_output_filter_handle(filter, NULL, r, r->connection);
-#ifndef NO_PROTOCOL
- if (ranges && (filter->proto_flags
- & (AP_FILTER_PROTO_NO_BYTERANGE
- | AP_FILTER_PROTO_CHANGE_LENGTH))) {
- ctx->range = apr_table_get(r->headers_in, "Range");
- apr_table_unset(r->headers_in, "Range");
- ranges = 0;
- }
-#endif
- }
-
- return;
-}
-
-static void filter_hooks(apr_pool_t *pool)
-{
- ap_hook_insert_filter(filter_insert, NULL, NULL, APR_HOOK_MIDDLE);
-}
-
-static void *filter_config(apr_pool_t *pool, char *x)
-{
- mod_filter_cfg *cfg = apr_palloc(pool, sizeof(mod_filter_cfg));
- cfg->live_filters = apr_hash_make(pool);
- cfg->chain = NULL;
- return cfg;
-}
-
-static void *filter_merge(apr_pool_t *pool, void *BASE, void *ADD)
-{
- mod_filter_cfg *base = BASE;
- mod_filter_cfg *add = ADD;
- mod_filter_chain *savelink = 0;
- mod_filter_chain *newlink;
- mod_filter_chain *p;
- mod_filter_cfg *conf = apr_palloc(pool, sizeof(mod_filter_cfg));
-
- conf->live_filters = apr_hash_overlay(pool, add->live_filters,
- base->live_filters);
- if (base->chain && add->chain) {
- for (p = base->chain; p; p = p->next) {
- newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain));
- if (savelink) {
- savelink->next = newlink;
- savelink = newlink;
- }
- else {
- conf->chain = savelink = newlink;
- }
- }
-
- for (p = add->chain; p; p = p->next) {
- newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain));
- savelink->next = newlink;
- savelink = newlink;
- }
- }
- else if (add->chain) {
- conf->chain = add->chain;
- }
- else {
- conf->chain = base->chain;
- }
-
- return conf;
-}
-
-static const command_rec filter_cmds[] = {
- AP_INIT_TAKE12("FilterDeclare", filter_declare, NULL, OR_OPTIONS,
- "filter-name [, filter-type]"),
- /** we don't have a TAKE4, so we have to use RAW_ARGS */
- AP_INIT_RAW_ARGS("FilterProvider", filter_provider, NULL, OR_OPTIONS,
- "filter-name, provider-name, dispatch--criterion, dispatch-match"),
- AP_INIT_ITERATE("FilterChain", filter_chain, NULL, OR_OPTIONS,
- "list of filter names with optional [+-=!@]"),
- AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, RSRC_CONF | ACCESS_CONF,
- "Debug level"),
-#ifndef NO_PROTOCOL
- AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_OPTIONS,
- "filter-name [provider-name] protocol-args"),
-#endif
- { NULL }
-};
-
-module AP_MODULE_DECLARE_DATA filter_module = {
- STANDARD20_MODULE_STUFF,
- filter_config,
- filter_merge,
- NULL,
- NULL,
- filter_cmds,
- filter_hooks
-};