summaryrefslogtreecommitdiff
path: root/modules/filters
diff options
context:
space:
mode:
authorArno Töll <debian@toell.net>2012-01-08 22:53:17 +0100
committerArno Töll <debian@toell.net>2012-01-08 22:53:17 +0100
commite072a2dd866b7cb9f14319b80326a4e7fd16fcdf (patch)
treea49dfc56d94a26011fe157835ff6cbe14edbd8a9 /modules/filters
parent0890390c00801651d08d3794e13b31a5dabbf5ef (diff)
downloadapache2-e072a2dd866b7cb9f14319b80326a4e7fd16fcdf.tar.gz
Imported Upstream version 2.3.16-beta
Diffstat (limited to 'modules/filters')
-rw-r--r--modules/filters/NWGNUextfiltr18
-rw-r--r--modules/filters/NWGNUmakefile18
-rw-r--r--modules/filters/NWGNUmod_data248
-rw-r--r--modules/filters/NWGNUmod_filter18
-rw-r--r--modules/filters/NWGNUmod_request248
-rw-r--r--modules/filters/NWGNUmodbuffer256
-rw-r--r--modules/filters/NWGNUmodsed259
-rw-r--r--modules/filters/NWGNUproxyhtml261
-rw-r--r--modules/filters/NWGNUratelimit256
-rw-r--r--modules/filters/NWGNUreflector256
-rw-r--r--modules/filters/NWGNUxml2enc258
-rw-r--r--modules/filters/config.m486
-rw-r--r--modules/filters/libsed.h175
-rw-r--r--modules/filters/mod_buffer.c342
-rw-r--r--modules/filters/mod_buffer.dsp111
-rw-r--r--modules/filters/mod_charset_lite.c160
-rw-r--r--modules/filters/mod_charset_lite.dep33
-rw-r--r--modules/filters/mod_charset_lite.mak353
-rw-r--r--modules/filters/mod_data.c254
-rw-r--r--modules/filters/mod_data.dsp111
-rw-r--r--modules/filters/mod_deflate.c346
-rw-r--r--modules/filters/mod_deflate.dep28
-rw-r--r--modules/filters/mod_deflate.mak353
-rw-r--r--modules/filters/mod_ext_filter.c107
-rw-r--r--modules/filters/mod_ext_filter.dep32
-rw-r--r--modules/filters/mod_ext_filter.mak353
-rw-r--r--modules/filters/mod_filter.c381
-rw-r--r--modules/filters/mod_filter.dep27
-rw-r--r--modules/filters/mod_filter.mak353
-rw-r--r--modules/filters/mod_include.c647
-rw-r--r--modules/filters/mod_include.dep36
-rw-r--r--modules/filters/mod_include.h8
-rw-r--r--modules/filters/mod_include.mak353
-rw-r--r--modules/filters/mod_proxy_html.c1266
-rw-r--r--modules/filters/mod_proxy_html.dsp123
-rw-r--r--modules/filters/mod_ratelimit.c313
-rw-r--r--modules/filters/mod_ratelimit.dsp115
-rw-r--r--modules/filters/mod_ratelimit.h51
-rw-r--r--modules/filters/mod_reflector.c232
-rw-r--r--modules/filters/mod_reflector.dsp111
-rw-r--r--modules/filters/mod_reqtimeout.c149
-rw-r--r--modules/filters/mod_reqtimeout.dep32
-rw-r--r--modules/filters/mod_reqtimeout.mak353
-rw-r--r--modules/filters/mod_request.c396
-rw-r--r--modules/filters/mod_request.dsp115
-rw-r--r--modules/filters/mod_sed.c537
-rw-r--r--modules/filters/mod_sed.dsp135
-rw-r--r--modules/filters/mod_substitute.c233
-rw-r--r--modules/filters/mod_substitute.dep29
-rw-r--r--modules/filters/mod_substitute.mak353
-rw-r--r--modules/filters/mod_xml2enc.c628
-rw-r--r--modules/filters/mod_xml2enc.dsp123
-rw-r--r--modules/filters/mod_xml2enc.h55
-rw-r--r--modules/filters/regexp.c599
-rw-r--r--modules/filters/regexp.h111
-rw-r--r--modules/filters/sed.h61
-rw-r--r--modules/filters/sed0.c1026
-rw-r--r--modules/filters/sed1.c1018
58 files changed, 11349 insertions, 3560 deletions
diff --git a/modules/filters/NWGNUextfiltr b/modules/filters/NWGNUextfiltr
index 16ae72a1..1fd57cb0 100644
--- a/modules/filters/NWGNUextfiltr
+++ b/modules/filters/NWGNUextfiltr
@@ -94,7 +94,7 @@ endif
NLM_NAME = extfiltr
#
-# This is used by the link '-desc ' directive.
+# This is used by the link '-desc ' directive.
# If left blank, NLM_NAME will be used.
#
NLM_DESCRIPTION = Apache $(VERSION_STR) External Filter Module
@@ -106,7 +106,7 @@ NLM_DESCRIPTION = Apache $(VERSION_STR) External Filter Module
NLM_THREAD_NAME = ExtFilter Module
#
-# If this is specified, it will override VERSION value in
+# If this is specified, it will override VERSION value in
# $(AP_WORK)/build/NWGNUenvironment.inc
#
NLM_VERSION =
@@ -138,11 +138,11 @@ NLM_CHECK_SYM =
NLM_FLAGS =
#
-# If this is specified it will be linked in with the XDCData option in the def
+# 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 =
+XDCDATA =
#
# If there is an NLM target, put it here
@@ -186,7 +186,7 @@ FILES_nlm_modules = \
# 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
#
@@ -205,15 +205,15 @@ FILES_nlm_Ximports = \
@httpd.imp \
@libc.imp \
$(EOLIST)
-
-#
+
+#
# Any symbols exported to here
#
FILES_nlm_exports = \
ext_filter_module \
$(EOLIST)
-#
+#
# These are the OBJ files needed to create the LIB target above.
# Paths must all use the '/' character
#
@@ -229,7 +229,7 @@ libs :: $(OBJDIR) $(TARGET_lib)
nlms :: libs $(TARGET_nlm)
#
-# Updated this target to create necessary directories and copy files to the
+# 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
diff --git a/modules/filters/NWGNUmakefile b/modules/filters/NWGNUmakefile
index 2b21b230..922abac9 100644
--- a/modules/filters/NWGNUmakefile
+++ b/modules/filters/NWGNUmakefile
@@ -154,12 +154,18 @@ XDCDATA =
TARGET_nlm = \
$(OBJDIR)/extfiltr.nlm \
$(OBJDIR)/charsetl.nlm \
+ $(OBJDIR)/mod_data.nlm \
$(OBJDIR)/mod_filter.nlm \
+ $(OBJDIR)/mod_request.nlm \
$(OBJDIR)/substitute.nlm \
+ $(OBJDIR)/modsed.nlm \
+ $(OBJDIR)/modbuffer.nlm \
+ $(OBJDIR)/ratelimit.nlm \
$(OBJDIR)/reqtimeout.nlm \
+ $(OBJDIR)/reflector.nlm \
$(EOLIST)
-# If the zlib libraries source exists then build the mod_deflate module
+# If the zlib library source exists then build the mod_deflate module
ifneq "$(ZLIBSDK)" ""
ifeq "$(wildcard $(ZLIBSDK))" "$(ZLIBSDK)"
TARGET_nlm += $(OBJDIR)/deflate.nlm \
@@ -167,6 +173,16 @@ TARGET_nlm += $(OBJDIR)/deflate.nlm \
endif
endif
+# If the libxml2 library source exists then build the mod_proxy_html module
+ifneq "$(LIBXML2SDK)" ""
+ifeq "$(wildcard $(LIBXML2SDK))" "$(LIBXML2SDK)"
+TARGET_nlm += \
+ $(OBJDIR)/proxyhtml.nlm \
+ $(OBJDIR)/xml2enc.nlm \
+ $(EOLIST)
+endif
+endif
+
#
# If there is an LIB target, put it here
#
diff --git a/modules/filters/NWGNUmod_data b/modules/filters/NWGNUmod_data
new file mode 100644
index 00000000..7f46e9aa
--- /dev/null
+++ b/modules/filters/NWGNUmod_data
@@ -0,0 +1,248 @@
+#
+# 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 += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(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_data
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Data 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/$(NLM_NAME).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)/$(NLM_NAME).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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ data_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUmod_filter b/modules/filters/NWGNUmod_filter
index 3bc38385..bf323ee7 100644
--- a/modules/filters/NWGNUmod_filter
+++ b/modules/filters/NWGNUmod_filter
@@ -94,7 +94,7 @@ endif
NLM_NAME = mod_filter
#
-# This is used by the link '-desc ' directive.
+# This is used by the link '-desc ' directive.
# If left blank, NLM_NAME will be used.
#
NLM_DESCRIPTION = Apache $(VERSION_STR) Filter Module
@@ -106,7 +106,7 @@ NLM_DESCRIPTION = Apache $(VERSION_STR) Filter Module
NLM_THREAD_NAME = Filter Module
#
-# If this is specified, it will override VERSION value in
+# If this is specified, it will override VERSION value in
# $(AP_WORK)/build/NWGNUenvironment.inc
#
NLM_VERSION =
@@ -138,11 +138,11 @@ NLM_CHECK_SYM =
NLM_FLAGS =
#
-# If this is specified it will be linked in with the XDCData option in the def
+# 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 =
+XDCDATA =
#
# If there is an NLM target, put it here
@@ -186,7 +186,7 @@ FILES_nlm_modules = \
# 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
#
@@ -205,15 +205,15 @@ FILES_nlm_Ximports = \
@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
#
@@ -229,7 +229,7 @@ libs :: $(OBJDIR) $(TARGET_lib)
nlms :: libs $(TARGET_nlm)
#
-# Updated this target to create necessary directories and copy files to the
+# 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
diff --git a/modules/filters/NWGNUmod_request b/modules/filters/NWGNUmod_request
new file mode 100644
index 00000000..21f53cc1
--- /dev/null
+++ b/modules/filters/NWGNUmod_request
@@ -0,0 +1,248 @@
+#
+# 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 += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(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_request
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Request Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Request 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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_request.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_request.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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ request_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUmodbuffer b/modules/filters/NWGNUmodbuffer
new file mode 100644
index 00000000..7652a358
--- /dev/null
+++ b/modules/filters/NWGNUmodbuffer
@@ -0,0 +1,256 @@
+#
+# 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 += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(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 = modbuffer
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Buffer Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = modbuffer
+
+#
+# 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/modbuffer.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_buffer.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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ buffer_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUmodsed b/modules/filters/NWGNUmodsed
new file mode 100644
index 00000000..158acb9d
--- /dev/null
+++ b/modules/filters/NWGNUmodsed
@@ -0,0 +1,259 @@
+#
+# 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 += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(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 = modsed
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) SED Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = modsed 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/modsed.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_sed.o \
+ $(OBJDIR)/regexp.o \
+ $(OBJDIR)/sed0.o \
+ $(OBJDIR)/sed1.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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ sed_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUproxyhtml b/modules/filters/NWGNUproxyhtml
new file mode 100644
index 00000000..5337f3b1
--- /dev/null
+++ b/modules/filters/NWGNUproxyhtml
@@ -0,0 +1,261 @@
+#
+# 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 += \
+ $(LIBXML2SDK)/include \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ -L$(LIBXML2SDK)/lib -llibxml2.lib \
+ $(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 = proxyhtml
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Proxy HTML Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Proxy HTTP 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/$(NLM_NAME).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_proxy_html.o \
+ $(OBJDIR)/libprews.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 = \
+ $(PRELUDE) \
+ $(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 \
+ proxy \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+# Don't link with Winsock if standard sockets are being used
+ifndef USE_STDSOCKETS
+FILES_nlm_Ximports += @ws2nlm.imp \
+ $(EOLIST)
+endif
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ proxy_html_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
+#
+
+vpath %.c ../arch/netware
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUratelimit b/modules/filters/NWGNUratelimit
new file mode 100644
index 00000000..f75c8140
--- /dev/null
+++ b/modules/filters/NWGNUratelimit
@@ -0,0 +1,256 @@
+#
+# 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 += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(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 = ratelimit
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Rate Limit Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = ratelimit
+
+#
+# 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/ratelimit.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_ratelimit.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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ ratelimit_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUreflector b/modules/filters/NWGNUreflector
new file mode 100644
index 00000000..67ca26d9
--- /dev/null
+++ b/modules/filters/NWGNUreflector
@@ -0,0 +1,256 @@
+#
+# 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 += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(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 = reflector
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Reflector Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = reflector
+
+#
+# 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/reflector.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_reflector.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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ reflector_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/NWGNUxml2enc b/modules/filters/NWGNUxml2enc
new file mode 100644
index 00000000..117832eb
--- /dev/null
+++ b/modules/filters/NWGNUxml2enc
@@ -0,0 +1,258 @@
+#
+# 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 += \
+ $(LIBXML2SDK)/include \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ -L$(LIBXML2SDK)/lib -llibxml2.lib \
+ $(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 = xml2enc
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) xml2enc Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Substitute 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 =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# 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 =
+
+#
+# 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)/$(NLM_NAME).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_xml2enc.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 = \
+ $(PRELUDE) \
+ $(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 = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ xml2enc_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 $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/filters/config.m4 b/modules/filters/config.m4
index 247d4f65..4ef2d3a5 100644
--- a/modules/filters/config.m4
+++ b/modules/filters/config.m4
@@ -4,18 +4,26 @@ dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]])
APACHE_MODPATH_INIT(filters)
-APACHE_MODULE(reqtimeout, Limit time waiting for request from client, , , most)
+APACHE_MODULE(buffer, Filter Buffering, , , most)
+APACHE_MODULE(data, RFC2397 data encoder, , , )
+APACHE_MODULE(ratelimit, Output Bandwidth Limiting, , , most)
+APACHE_MODULE(reqtimeout, Limit time waiting for request from client, , , yes)
APACHE_MODULE(ext_filter, external filter module, , , most)
-APACHE_MODULE(include, Server Side Includes, , , yes)
+APACHE_MODULE(request, Request Body Filtering, , , most)
+APACHE_MODULE(include, Server Side Includes, , , most)
APACHE_MODULE(filter, Smart Filtering, , , yes)
+APACHE_MODULE(reflector, Reflect request through the output filter stack, , , )
APACHE_MODULE(substitute, response content rewrite-like filtering, , , most)
+sed_obj="mod_sed.lo sed0.lo sed1.lo regexp.lo"
+APACHE_MODULE(sed, filter request and/or response bodies through sed, $sed_obj, , most)
+
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)
+ APACHE_MODULE(charset_lite, character set translation. Enabled by default only on EBCDIC systems., , , yes)
else
- APACHE_MODULE(charset_lite, character set translation, , , no)
+ APACHE_MODULE(charset_lite, character set translation. Enabled by default only on EBCDIC systems., , , )
fi
@@ -24,6 +32,7 @@ APACHE_MODULE(deflate, Deflate transfer encoding support, , , most, [
[
if test "x$withval" != "xyes" && test "x$withval" != "x"; then
ap_zlib_base="$withval"
+ ap_zlib_with="yes"
fi
])
if test "x$ap_zlib_base" = "x"; then
@@ -48,27 +57,82 @@ APACHE_MODULE(deflate, Deflate transfer encoding support, , , most, [
ap_save_includes=$INCLUDES
ap_save_ldflags=$LDFLAGS
ap_save_cppflags=$CPPFLAGS
+ ap_zlib_ldflags=""
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 $INCLUDES"
APR_ADDTO(LDFLAGS, [-L${ap_zlib_base}/lib])
+ APR_ADDTO(ap_zlib_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])
+ APR_ADDTO(ap_zlib_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>], [int i = Z_OK;],
- [AC_MSG_RESULT(found)
- APR_SETVAR(MOD_DEFLATE_LDADD, [-lz])],
- [AC_MSG_RESULT(not found)
- enable_deflate=no
- INCLUDES=$ap_save_includes
- LDFLAGS=$ap_save_ldflags])
- APR_REMOVEFROM(LIBS, [-lz])
+ [AC_MSG_RESULT(found)
+ APR_ADDTO(MOD_DEFLATE_LDADD, [$ap_zlib_ldflags -lz])],
+ [AC_MSG_RESULT(not found)
+ enable_deflate=no
+ INCLUDES=$ap_save_includes
+ if test "x$ap_zlib_with" = "x"; then
+ AC_MSG_WARN([... Error, zlib was missing or unusable])
+ else
+ AC_MSG_ERROR([... Error, zlib was missing or unusable])
+ fi
+ ])
+ LDFLAGS=$ap_save_ldflags
CPPFLAGS=$ap_save_cppflags
+ APR_REMOVEFROM(LIBS, [-lz])
fi
])
+AC_DEFUN(FIND_LIBXML2, [
+ AC_CACHE_CHECK([for libxml2], [ac_cv_libxml2], [
+ AC_ARG_WITH(libxml2,
+ [APACHE_HELP_STRING(--with-libxml2,location for libxml2)],
+ [test_paths="${with_libxml2}"],
+ [test_paths="/usr/include/libxml2 /usr/local/include/libxml2 /usr/include /usr/local/include"]
+ )
+ AC_MSG_CHECKING(for libxml2)
+ xml2_path=""
+ for x in ${test_paths}; do
+ if test -f "${x}/libxml/parser.h"; then
+ xml2_path="${x}"
+ break
+ fi
+ done
+ if test -n "${xml2_path}" ; then
+ ac_cv_libxml2=yes
+ XML2_INCLUDES="${xml2_path}"
+ else
+ ac_cv_libxml2=no
+ fi
+ ])
+])
+
+APACHE_MODULE(xml2enc, i18n support for markup filters, , , , [
+ FIND_LIBXML2
+ if test "$ac_cv_libxml2" = "yes" ; then
+ APR_ADDTO(CFLAGS, [-I${XML2_INCLUDES}])
+ APR_ADDTO(MOD_XML2ENC_LDADD, [-lxml2])
+ else
+ enable_xml2enc=no
+ fi
+])
+APACHE_MODULE(proxy_html, Fix HTML Links in a Reverse Proxy, , , , [
+ FIND_LIBXML2
+ if test "$ac_cv_libxml2" = "yes" ; then
+ APR_ADDTO(CFLAGS, [-I${XML2_INCLUDES}])
+ APR_ADDTO(MOD_PROXY_HTML_LDADD, [-lxml2])
+ else
+ enable_proxy_html=no
+ fi
+]
+)
+
+APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
+
APACHE_MODPATH_FINISH
diff --git a/modules/filters/libsed.h b/modules/filters/libsed.h
new file mode 100644
index 00000000..a889d50a
--- /dev/null
+++ b/modules/filters/libsed.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1984 AT&T
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef LIBSED_H
+#define LIBSED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <limits.h>
+
+#include "apr_file_io.h"
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+
+#define SED_NLINES 256
+#define SED_DEPTH 20
+#define SED_LABSIZE 50
+#define SED_ABUFSIZE 20
+
+typedef struct sed_reptr_s sed_reptr_t;
+
+struct sed_reptr_s {
+ sed_reptr_t *next;
+ char *ad1;
+ char *ad2;
+ char *re1;
+ sed_reptr_t *lb1;
+ char *rhs;
+ int findex;
+ char command;
+ int gfl;
+ char pfl;
+ char negfl;
+ int nrep;
+};
+
+typedef struct sed_label_s sed_label_t;
+
+struct sed_label_s {
+ char asc[9];
+ sed_reptr_t *chain;
+ sed_reptr_t *address;
+};
+
+typedef apr_status_t (sed_err_fn_t)(void *data, const char *error);
+typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz);
+
+typedef struct sed_commands_s sed_commands_t;
+#define NWFILES 11 /* 10 plus one for standard output */
+
+struct sed_commands_s {
+ sed_err_fn_t *errfn;
+ void *data;
+
+ unsigned lsize;
+ char *linebuf;
+ char *lbend;
+ const char *saveq;
+
+ char *cp;
+ char *lastre;
+ char *respace;
+ char sseof;
+ char *reend;
+ const char *earg;
+ int eflag;
+ int gflag;
+ int nflag;
+ apr_int64_t tlno[SED_NLINES];
+ int nlno;
+ int depth;
+
+ char *fname[NWFILES];
+ int nfiles;
+
+ sed_label_t ltab[SED_LABSIZE];
+ sed_label_t *labtab;
+ sed_label_t *lab;
+ sed_label_t *labend;
+
+ sed_reptr_t **cmpend[SED_DEPTH];
+ sed_reptr_t *ptrspace;
+ sed_reptr_t *ptrend;
+ sed_reptr_t *rep;
+ int nrep;
+ apr_pool_t *pool;
+ int canbefinal;
+};
+
+typedef struct sed_eval_s sed_eval_t;
+
+struct sed_eval_s {
+ sed_err_fn_t *errfn;
+ sed_write_fn_t *writefn;
+ void *data;
+
+ sed_commands_t *commands;
+
+ apr_int64_t lnum;
+ void *fout;
+
+ unsigned lsize;
+ char *linebuf;
+ char *lspend;
+
+ unsigned hsize;
+ char *holdbuf;
+ char *hspend;
+
+ unsigned gsize;
+ char *genbuf;
+ char *lcomend;
+
+ apr_file_t *fcode[NWFILES];
+ sed_reptr_t *abuf[SED_ABUFSIZE];
+ sed_reptr_t **aptr;
+ sed_reptr_t *pending;
+ unsigned char *inar;
+ int nrep;
+
+ int dolflag;
+ int sflag;
+ int jflag;
+ int delflag;
+ int lreadyflag;
+ int quitflag;
+ int finalflag;
+ int numpass;
+ int nullmatch;
+ int col;
+ apr_pool_t *pool;
+};
+
+apr_status_t sed_init_commands(sed_commands_t *commands, sed_err_fn_t *errfn, void *data,
+ apr_pool_t *p);
+apr_status_t sed_compile_string(sed_commands_t *commands, const char *s);
+apr_status_t sed_compile_file(sed_commands_t *commands, apr_file_t *fin);
+char* sed_get_finalize_error(const sed_commands_t *commands, apr_pool_t* pool);
+int sed_canbe_finalized(const sed_commands_t *commands);
+void sed_destroy_commands(sed_commands_t *commands);
+
+apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands,
+ sed_err_fn_t *errfn, void *data,
+ sed_write_fn_t *writefn, apr_pool_t *p);
+apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data);
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout);
+apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout);
+apr_status_t sed_finalize_eval(sed_eval_t *eval, void *f);
+void sed_destroy_eval(sed_eval_t *eval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSED_H */
diff --git a/modules/filters/mod_buffer.c b/modules/filters/mod_buffer.c
new file mode 100644
index 00000000..cf552aa7
--- /dev/null
+++ b/modules/filters/mod_buffer.c
@@ -0,0 +1,342 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+ * mod_buffer.c --- Buffer the input and output filter stacks, collapse
+ * many small buckets into fewer large buckets.
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_lib.h"
+
+#include "ap_config.h"
+#include "util_filter.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "http_request.h"
+
+static const char bufferFilterName[] = "BUFFER";
+module AP_MODULE_DECLARE_DATA buffer_module;
+
+#define DEFAULT_BUFFER_SIZE 128*1024
+
+typedef struct buffer_conf {
+ apr_off_t size; /* size of the buffer */
+ int size_set; /* has the size been set */
+} buffer_conf;
+
+typedef struct buffer_ctx {
+ apr_bucket_brigade *bb;
+ apr_bucket_brigade *tmp;
+ buffer_conf *conf;
+ apr_off_t remaining;
+ int seen_eos;
+} buffer_ctx;
+
+/**
+ * Buffer buckets being written to the output filter stack.
+ */
+static apr_status_t buffer_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) {
+ apr_bucket *e;
+ request_rec *r = f->r;
+ buffer_ctx *ctx = f->ctx;
+ apr_status_t rv = APR_SUCCESS;
+ int move = 0;
+
+ /* first time in? create a context */
+ if (!ctx) {
+
+ /* buffering won't work on subrequests, it would be nice if
+ * it did. Within subrequests, we have no EOS to check for,
+ * so we don't know when to flush the buffer to the network
+ */
+ if (f->r->main) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
+ ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
+ ctx->conf = ap_get_module_config(f->r->per_dir_config, &buffer_module);
+
+ }
+
+ /* Do nothing if asked to filter nothing. */
+ if (APR_BRIGADE_EMPTY(bb)) {
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ /* Empty buffer means we can potentially optimise below */
+ if (APR_BRIGADE_EMPTY(ctx->bb)) {
+ move = 1;
+ }
+
+ while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) {
+ const char *data;
+ apr_off_t len;
+ apr_size_t size;
+
+ e = APR_BRIGADE_FIRST(bb);
+
+ /* EOS means we are done. */
+ if (APR_BUCKET_IS_EOS(e)) {
+
+ /* should we add an etag? */
+
+ /* pass the EOS across */
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+
+ /* pass what we have down the chain */
+ rv = ap_pass_brigade(f->next, ctx->bb);
+ continue;
+ }
+
+ /* A flush takes precedence over buffering */
+ if (APR_BUCKET_IS_FLUSH(e)) {
+
+ /* pass the flush bucket across */
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+
+ /* pass what we have down the chain */
+ rv = ap_pass_brigade(f->next, ctx->bb);
+ continue;
+ }
+
+ /* metadata buckets are preserved as is */
+ if (APR_BUCKET_IS_METADATA(e)) {
+ /*
+ * Remove meta data bucket from old brigade and insert into the
+ * new.
+ */
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+ continue;
+ }
+
+ /* is our buffer full?
+ * If so, send what we have down the filter chain. If the buffer
+ * gets full, we can no longer compute a content length.
+ */
+ apr_brigade_length(ctx->bb, 1, &len);
+ if (len > ctx->conf->size) {
+
+ /* pass what we have down the chain */
+ rv = ap_pass_brigade(f->next, ctx->bb);
+ if (rv) {
+ /* should break out of the loop, since our write to the client
+ * failed in some way. */
+ continue;
+ }
+ }
+
+ /* at this point we are ready to buffer.
+ * Buffering takes advantage of an optimisation in the handling of
+ * bucket brigades. Heap buckets are always created at a fixed
+ * size, regardless of the size of the data placed into them.
+ * The apr_brigade_write() call will first try and pack the data
+ * into any free space in the most recent heap bucket, before
+ * allocating a new bucket if necessary.
+ */
+ if (APR_SUCCESS == (rv = apr_bucket_read(e, &data, &size,
+ APR_BLOCK_READ))) {
+
+ /* further optimisation: if the buckets are already heap
+ * buckets, and the buckets stay exactly APR_BUCKET_BUFF_SIZE
+ * long (as they would be if we were reading bits of a
+ * large bucket), then move the buckets instead of copying
+ * them.
+ */
+ if (move && APR_BUCKET_IS_HEAP(e)) {
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+ if (APR_BUCKET_BUFF_SIZE != size) {
+ move = 0;
+ }
+ } else {
+ apr_brigade_write(ctx->bb, NULL, NULL, data, size);
+ apr_bucket_delete(e);
+ }
+
+ }
+
+ }
+
+ return rv;
+
+}
+
+/**
+ * Buffer buckets being read from the input filter stack.
+ */
+static apr_status_t buffer_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_bucket *e, *after;
+ apr_status_t rv;
+ buffer_ctx *ctx = f->ctx;
+
+ /* buffer on main requests only */
+ if (!ap_is_initial_req(f->r)) {
+ ap_remove_input_filter(f);
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
+ }
+
+ /* first time in? create a context */
+ if (!ctx) {
+ ctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
+ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+ ctx->tmp = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+ ctx->conf = ap_get_module_config(f->r->per_dir_config, &buffer_module);
+ }
+
+ /* just get out of the way of things we don't want. */
+ if (mode != AP_MODE_READBYTES) {
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
+ }
+
+ /* if our buffer is empty, read off the network until the buffer is full */
+ if (APR_BRIGADE_EMPTY(ctx->bb)) {
+ ctx->remaining = ctx->conf->size;
+
+ while (!ctx->seen_eos && ctx->remaining > 0) {
+ const char *data;
+ apr_size_t size = 0;
+
+ rv = ap_get_brigade(f->next, ctx->tmp, mode, block, ctx->remaining);
+
+ /* if an error was received, bail out now. If the error is
+ * EAGAIN and we have not yet seen an EOS, we will definitely
+ * be called again, at which point we will send our buffered
+ * data. Instead of sending EAGAIN, some filters return an
+ * empty brigade instead when data is not yet available. In
+ * this case, pass through the APR_SUCCESS and emulate the
+ * underlying filter.
+ */
+ if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(ctx->tmp)) {
+ return rv;
+ }
+
+ for (e = APR_BRIGADE_FIRST(ctx->tmp); e != APR_BRIGADE_SENTINEL(
+ ctx->tmp); e = APR_BUCKET_NEXT(e)) {
+
+ /* if we see an EOS, we are done */
+ if (APR_BUCKET_IS_EOS(e)) {
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+ ctx->seen_eos = 1;
+ break;
+ }
+
+ /* flush buckets clear the buffer */
+ if (APR_BUCKET_IS_FLUSH(e)) {
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+ break;
+ }
+
+ /* pass metadata buckets through */
+ if (APR_BUCKET_IS_METADATA(e)) {
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+ continue;
+ }
+
+ /* read the bucket in, pack it into the buffer */
+ if (APR_SUCCESS == (rv = apr_bucket_read(e, &data, &size,
+ APR_BLOCK_READ))) {
+ apr_brigade_write(ctx->bb, NULL, NULL, data, size);
+ ctx->remaining -= size;
+ apr_bucket_delete(e);
+ } else {
+ return rv;
+ }
+
+ }
+ }
+ }
+
+ /* give the caller the data they asked for from the buffer */
+ apr_brigade_partition(ctx->bb, readbytes, &after);
+ e = APR_BRIGADE_FIRST(ctx->bb);
+ while (e != after) {
+ if (APR_BUCKET_IS_EOS(e)) {
+ /* last bucket read, step out of the way */
+ ap_remove_input_filter(f);
+ }
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ e = APR_BRIGADE_FIRST(ctx->bb);
+ }
+
+ return APR_SUCCESS;
+}
+
+static void *create_buffer_config(apr_pool_t *p, char *dummy) {
+ buffer_conf *new = (buffer_conf *) apr_pcalloc(p, sizeof(buffer_conf));
+
+ new->size_set = 0; /* unset */
+ new->size = DEFAULT_BUFFER_SIZE; /* default size */
+
+ return (void *) new;
+}
+
+static void *merge_buffer_config(apr_pool_t *p, void *basev, void *addv) {
+ buffer_conf *new = (buffer_conf *) apr_pcalloc(p, sizeof(buffer_conf));
+ buffer_conf *add = (buffer_conf *) addv;
+ buffer_conf *base = (buffer_conf *) basev;
+
+ new->size = (add->size_set == 0) ? base->size : add->size;
+ new->size_set = add->size_set || base->size_set;
+
+ return new;
+}
+
+static const char *set_buffer_size(cmd_parms *cmd, void *dconf, const char *arg) {
+ buffer_conf *conf = dconf;
+
+ if (APR_SUCCESS != apr_strtoff(&(conf->size), arg, NULL, 10) || conf->size
+ <= 0) {
+ return "BufferSize must be a size in bytes, and greater than zero";
+ }
+ conf->size_set = 1;
+
+ return NULL;
+}
+
+static const command_rec buffer_cmds[] = { AP_INIT_TAKE1("BufferSize",
+ set_buffer_size, NULL, ACCESS_CONF,
+ "Maximum size of the buffer used by the buffer filter"), { NULL } };
+
+static void register_hooks(apr_pool_t *p) {
+ ap_register_output_filter(bufferFilterName, buffer_out_filter, NULL,
+ AP_FTYPE_CONTENT_SET);
+ ap_register_input_filter(bufferFilterName, buffer_in_filter, NULL,
+ AP_FTYPE_CONTENT_SET);
+}
+
+AP_DECLARE_MODULE(buffer) = {
+ STANDARD20_MODULE_STUFF,
+ create_buffer_config, /* create per-directory config structure */
+ merge_buffer_config, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ buffer_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/filters/mod_buffer.dsp b/modules/filters/mod_buffer.dsp
new file mode 100644
index 00000000..26834f57
--- /dev/null
+++ b/modules/filters/mod_buffer.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_buffer" - 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_buffer - Win32 Release
+!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_buffer.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_buffer.mak" CFG="mod_buffer - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_buffer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_buffer - 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_buffer - 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" /D "HAVE_ZUTIL_H" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_buffer_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_buffer.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_buffer.so" /d LONG_NAME="buffer_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_buffer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_buffer.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_buffer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_buffer.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_buffer.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_buffer - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "HAVE_ZUTIL_H" /Fd"Debug\mod_buffer_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_buffer.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_buffer.so" /d LONG_NAME="buffer_module for Apache"
+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 /out:".\Debug\mod_buffer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_buffer.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_buffer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_buffer.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_buffer.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_buffer - Win32 Release"
+# Name "mod_buffer - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_buffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/filters/mod_charset_lite.c b/modules/filters/mod_charset_lite.c
index 76bbe551..25f1ecb2 100644
--- a/modules/filters/mod_charset_lite.c
+++ b/modules/filters/mod_charset_lite.c
@@ -26,7 +26,7 @@
#include "httpd.h"
#include "http_config.h"
-#define CORE_PRIVATE
+
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
@@ -70,8 +70,6 @@ typedef enum {
#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()? */
@@ -107,19 +105,12 @@ typedef struct charset_req_t {
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;
}
@@ -133,8 +124,6 @@ static void *merge_charset_dir_conf(apr_pool_t *p, void *basev, void *overridesv
* 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 =
@@ -187,9 +176,6 @@ static const char *add_charset_options(cmd_parms *cmd, void *in_dc,
else if (!strcasecmp(flag, "NoTranslateAllMimeTypes")) {
dc->force_xlate = FX_NOFORCE;
}
- else if (!strncasecmp(flag, "DebugLevel=", 11)) {
- dc->debug = atoi(flag + 11);
- }
else {
return apr_pstrcat(cmd->temp_pool,
"Invalid CharsetOptions option: ",
@@ -212,29 +198,25 @@ static int find_code_page(request_rec *r)
charset_filter_ctx_t *input_ctx, *output_ctx;
apr_status_t rv;
- 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->filename : "(none)",
- 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);
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
+ "uri: %s file: %s method: %d "
+ "imt: %s flags: %s%s%s %s->%s",
+ r->uri,
+ r->filename ? r->filename : "(none)",
+ 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");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01448)
+ "incomplete configuration: src %s, dst %s",
+ dc->charset_source ? dc->charset_source : "unspecified",
+ dc->charset_default ? dc->charset_default : "unspecified");
return DECLINED;
}
@@ -267,7 +249,7 @@ static int find_code_page(request_rec *r)
reqinfo->dc = dc;
output_ctx->dc = dc;
- output_ctx->tmpbb = apr_brigade_create(r->pool,
+ output_ctx->tmpbb = apr_brigade_create(r->pool,
r->connection->bucket_alloc);
ap_set_module_config(r->request_config, &charset_lite_module, reqinfo);
@@ -289,7 +271,7 @@ static int find_code_page(request_rec *r)
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,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01449)
"can't open translation %s->%s",
dc->charset_default, dc->charset_source);
return HTTP_INTERNAL_SERVER_ERROR;
@@ -337,12 +319,10 @@ static void xlate_insert_filter(request_rec *r)
charset_dir_t *dc = ap_get_module_config(r->per_dir_config,
&charset_lite_module);
- if (dc && (dc->implicit_add == IA_NOIMPADD)) {
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
- "xlate output filter not added implicitly because "
- "CharsetOptions included 'NoImplicitAdd'");
- }
+ if (dc && (dc->implicit_add == IA_NOIMPADD)) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, r,
+ "xlate output filter not added implicitly because "
+ "CharsetOptions included 'NoImplicitAdd'");
return;
}
@@ -351,25 +331,21 @@ static void xlate_insert_filter(request_rec *r)
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");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 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");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
+ "xlate input filter not added implicitly because %s",
+ !reqinfo->input_ctx ?
+ "no input configuration available" :
+ "another module added the filter");
}
}
@@ -503,19 +479,19 @@ static void log_xlate_error(ap_filter_t *f, apr_status_t rv)
switch(ctx->ees) {
case EES_LIMIT:
rv = 0;
- msg = "xlate filter - a built-in restriction was encountered";
+ msg = APLOGNO(02193) "xlate filter - a built-in restriction was encountered";
break;
case EES_BAD_INPUT:
rv = 0;
- msg = "xlate filter - an input character was invalid";
+ msg = APLOGNO(02194) "xlate filter - an input character was invalid";
break;
case EES_BUCKET_READ:
rv = 0;
- msg = "xlate filter - bucket read routine failed";
+ msg = APLOGNO(02195) "xlate filter - bucket read routine failed";
break;
case EES_INCOMPLETE_CHAR:
rv = 0;
- strcpy(msgbuf, "xlate filter - incomplete char at end of input - ");
+ strcpy(msgbuf, APLOGNO(02196) "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),
@@ -525,13 +501,12 @@ static void log_xlate_error(ap_filter_t *f, apr_status_t rv)
msg = msgbuf;
break;
case EES_DOWNSTREAM:
- msg = "xlate filter - an error occurred in a lower filter";
+ msg = APLOGNO(02197) "xlate filter - an error occurred in a lower filter";
break;
default:
- msg = "xlate filter - returning error";
+ msg = APLOGNO(02198) "xlate filter - returning error";
}
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
- "%s", msg);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "%s", msg);
}
/* chk_filter_chain() is called once per filter instance; it tries to
@@ -569,7 +544,6 @@ 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) {
@@ -603,11 +577,11 @@ static void chk_filter_chain(ap_filter_t *f)
*/
if (last_xlate_ctx == f->ctx) {
last_xlate_ctx->noop = 1;
- if (debug >= DBGLVL_PMC) {
+ if (APLOGrtrace1(f->r)) {
const char *symbol = output ? "->" : "<-";
ap_log_rerror(APLOG_MARK, APLOG_DEBUG,
- 0, f->r,
+ 0, f->r, APLOGNO(01451)
"%s %s - disabling "
"translation %s%s%s; existing "
"translation %s%s%s",
@@ -625,7 +599,7 @@ static void chk_filter_chain(ap_filter_t *f)
const char *symbol = output ? "->" : "<-";
ap_log_rerror(APLOG_MARK, APLOG_ERR,
- 0, f->r,
+ 0, f->r, APLOGNO(01452)
"chk_filter_chain() - can't disable "
"translation %s%s%s; existing "
"translation %s%s%s",
@@ -812,9 +786,9 @@ static apr_status_t xlate_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
/* Check the mime type to see if translation should be performed.
*/
if (!ctx->noop && ctx->xlate == NULL) {
- const char *mime_type = f->r->content_type ? f->r->content_type : ap_default_type(f->r);
+ const char *mime_type = f->r->content_type;
- if (strncasecmp(mime_type, "text/", 5) == 0 ||
+ if (mime_type && (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.
@@ -830,13 +804,13 @@ static apr_status_t xlate_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
*/
strcmp(mime_type, DIR_MAGIC_TYPE) == 0 ||
#endif
- strncasecmp(mime_type, "message/", 8) == 0 ||
- dc->force_xlate == FX_FORCE) {
+ strncasecmp(mime_type, "message/", 8) == 0 ||
+ dc->force_xlate == FX_FORCE)) {
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,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01453)
"can't open translation %s->%s",
dc->charset_source, dc->charset_default);
ctx->noop = 1;
@@ -849,21 +823,19 @@ static apr_status_t xlate_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
}
else {
ctx->noop = 1;
- if (dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r,
+ if (mime_type) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 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)");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 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);
@@ -1032,13 +1004,11 @@ static int xlate_in_filter(ap_filter_t *f, apr_bucket_brigade *bb,
}
}
- 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)");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 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);
@@ -1054,11 +1024,9 @@ static int xlate_in_filter(ap_filter_t *f, apr_bucket_brigade *bb,
* Processing of chunked request bodies is not impacted by this
* filter since the the length was not declared anyway.
*/
- if (dc->debug >= DBGLVL_PMC) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r,
- "Request body length may change, resulting in "
- "misprocessing by some modules or scripts");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r,
+ "Request body length may change, resulting in "
+ "misprocessing by some modules or scripts");
}
}
@@ -1143,7 +1111,7 @@ static const command_rec cmds[] =
NULL,
OR_FILEINFO,
"valid options: ImplicitAdd, NoImplicitAdd, TranslateAllMimeTypes, "
- "NoTranslateAllMimeTypes, DebugLevel=n"),
+ "NoTranslateAllMimeTypes"),
{NULL}
};
@@ -1157,7 +1125,7 @@ static void charset_register_hooks(apr_pool_t *p)
AP_FTYPE_RESOURCE);
}
-module AP_MODULE_DECLARE_DATA charset_lite_module =
+AP_DECLARE_MODULE(charset_lite) =
{
STANDARD20_MODULE_STUFF,
create_charset_dir_conf,
diff --git a/modules/filters/mod_charset_lite.dep b/modules/filters/mod_charset_lite.dep
deleted file mode 100644
index e6f20e7d..00000000
--- a/modules/filters/mod_charset_lite.dep
+++ /dev/null
@@ -1,33 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_charset_lite.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_charset_lite.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.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\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_charset.h"\
- "..\..\include\util_filter.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_hash.h"\
- "..\..\srclib\apr\include\apr_lib.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_portable.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
-
diff --git a/modules/filters/mod_charset_lite.mak b/modules/filters/mod_charset_lite.mak
deleted file mode 100644
index 8870f9ad..00000000
--- a/modules/filters/mod_charset_lite.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_charset_lite.dsp
-!IF "$(CFG)" == ""
-CFG=mod_charset_lite - Win32 Debug
-!MESSAGE No configuration specified. Defaulting to mod_charset_lite - Win32 Debug.
-!ENDIF
-
-!IF "$(CFG)" != "mod_charset_lite - Win32 Release" && "$(CFG)" != "mod_charset_lite - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_charset_lite.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_charset_lite.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_charset_lite.obj"
- -@erase "$(INTDIR)\mod_charset_lite.res"
- -@erase "$(INTDIR)\mod_charset_lite_src.idb"
- -@erase "$(INTDIR)\mod_charset_lite_src.pdb"
- -@erase "$(OUTDIR)\mod_charset_lite.exp"
- -@erase "$(OUTDIR)\mod_charset_lite.lib"
- -@erase "$(OUTDIR)\mod_charset_lite.pdb"
- -@erase "$(OUTDIR)\mod_charset_lite.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_charset_lite_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_charset_lite.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_charset_lite.so" /d LONG_NAME="charset_lite_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_charset_lite.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_charset_lite.pdb" /debug /out:"$(OUTDIR)\mod_charset_lite.so" /implib:"$(OUTDIR)\mod_charset_lite.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_charset_lite.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_charset_lite.obj" \
- "$(INTDIR)\mod_charset_lite.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_charset_lite.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_charset_lite.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_charset_lite.so"
- if exist .\Release\mod_charset_lite.so.manifest mt.exe -manifest .\Release\mod_charset_lite.so.manifest -outputresource:.\Release\mod_charset_lite.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_charset_lite.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_charset_lite.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_charset_lite.obj"
- -@erase "$(INTDIR)\mod_charset_lite.res"
- -@erase "$(INTDIR)\mod_charset_lite_src.idb"
- -@erase "$(INTDIR)\mod_charset_lite_src.pdb"
- -@erase "$(OUTDIR)\mod_charset_lite.exp"
- -@erase "$(OUTDIR)\mod_charset_lite.lib"
- -@erase "$(OUTDIR)\mod_charset_lite.pdb"
- -@erase "$(OUTDIR)\mod_charset_lite.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_charset_lite_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_charset_lite.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_charset_lite.so" /d LONG_NAME="charset_lite_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_charset_lite.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_charset_lite.pdb" /debug /out:"$(OUTDIR)\mod_charset_lite.so" /implib:"$(OUTDIR)\mod_charset_lite.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_charset_lite.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_charset_lite.obj" \
- "$(INTDIR)\mod_charset_lite.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_charset_lite.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_charset_lite.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_charset_lite.so"
- if exist .\Debug\mod_charset_lite.so.manifest mt.exe -manifest .\Debug\mod_charset_lite.so.manifest -outputresource:.\Debug\mod_charset_lite.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_charset_lite.dep")
-!INCLUDE "mod_charset_lite.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_charset_lite.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release" || "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_charset_lite - Win32 Release"
-
-
-"$(INTDIR)\mod_charset_lite.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_charset_lite.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_charset_lite.so" /d LONG_NAME="charset_lite_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_charset_lite - Win32 Debug"
-
-
-"$(INTDIR)\mod_charset_lite.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_charset_lite.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_charset_lite.so" /d LONG_NAME="charset_lite_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_charset_lite.c
-
-"$(INTDIR)\mod_charset_lite.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_data.c b/modules/filters/mod_data.c
new file mode 100644
index 00000000..83284dd2
--- /dev/null
+++ b/modules/filters/mod_data.c
@@ -0,0 +1,254 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+ * mod_data.c --- Turn the response into an rfc2397 data URL, suitable for
+ * displaying as inline content on a page.
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_base64.h"
+#include "apr_lib.h"
+
+#include "ap_config.h"
+#include "util_filter.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "http_request.h"
+#include "http_protocol.h"
+
+#define DATA_FILTER "DATA"
+
+module AP_MODULE_DECLARE_DATA data_module;
+
+typedef struct data_ctx
+{
+ unsigned char overflow[3];
+ int count;
+ apr_bucket_brigade *bb;
+} data_ctx;
+
+/**
+ * Create a data URL as follows:
+ *
+ * data:[<mime-type>;][charset=<charset>;]base64,<payload>
+ *
+ * Where:
+ *
+ * mime-type: The mime type of the original response.
+ * charset: The optional character set corresponding to the mime type.
+ * payload: A base64 version of the response body.
+ *
+ * The content type of the response is set to text/plain.
+ *
+ * The Content-Length header, if present, is updated with the new content
+ * length based on the increase in size expected from the base64 conversion.
+ * If the Content-Length header is too large to fit into an int, we remove
+ * the Content-Length header instead.
+ */
+static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
+{
+ apr_bucket *e, *ee;
+ request_rec *r = f->r;
+ data_ctx *ctx = f->ctx;
+ apr_status_t rv = APR_SUCCESS;
+
+ /* first time in? create a context */
+ if (!ctx) {
+ char *type;
+ char *charset = NULL;
+ char *end;
+ const char *content_length;
+
+ /* base64-ing won't work on subrequests, it would be nice if
+ * it did. Within subrequests, we have no EOS to check for,
+ * so we don't know when to flush the tail to the network.
+ */
+ if (!ap_is_initial_req(f->r)) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
+ ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
+
+ type = apr_pstrdup(r->pool, r->content_type);
+ if (type) {
+ charset = strchr(type, ' ');
+ if (charset) {
+ *charset++ = 0;
+ end = strchr(charset, ' ');
+ if (end) {
+ *end++ = 0;
+ }
+ }
+ }
+
+ apr_brigade_printf(ctx->bb, NULL, NULL, "data:%s%s;base64,",
+ type ? type : "", charset ? charset : "");
+
+ content_length = apr_table_get(r->headers_out, "Content-Length");
+ if (content_length) {
+ apr_off_t len, clen;
+ apr_brigade_length(ctx->bb, 1, &len);
+ clen = apr_atoi64(content_length);
+ if (clen >= 0 && clen < APR_INT32_MAX) {
+ ap_set_content_length(r, len + apr_base64_encode_len(clen) - 1);
+ }
+ else {
+ apr_table_unset(r->headers_out, "Content-Length");
+ }
+ }
+
+ ap_set_content_type(r, "text/plain");
+
+ }
+
+ /* Do nothing if asked to filter nothing. */
+ if (APR_BRIGADE_EMPTY(bb)) {
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) {
+ const char *data;
+ apr_size_t size;
+ apr_size_t tail;
+ apr_size_t len;
+ /* buffer big enough for 8000 encoded bytes (6000 raw bytes) and terminator */
+ char buffer[APR_BUCKET_BUFF_SIZE + 1];
+ char encoded[((sizeof(ctx->overflow)) / 3) * 4 + 1];
+
+ e = APR_BRIGADE_FIRST(bb);
+
+ /* EOS means we are done. */
+ if (APR_BUCKET_IS_EOS(e)) {
+
+ /* write away the tail */
+ if (ctx->count) {
+ len = apr_base64_encode_binary(encoded, ctx->overflow,
+ ctx->count);
+ apr_brigade_write(ctx->bb, NULL, NULL, encoded, len - 1);
+ ctx->count = 0;
+ }
+
+ /* pass the EOS across */
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+
+ /* pass what we have down the chain */
+ ap_remove_output_filter(f);
+ rv = ap_pass_brigade(f->next, ctx->bb);
+
+ /* pass any stray buckets after the EOS down the stack */
+ if ((APR_SUCCESS == rv) && (!APR_BRIGADE_EMPTY(bb))) {
+ rv = ap_pass_brigade(f->next, bb);
+ }
+ continue;
+ }
+
+ /* flush what we can, we can't flush the tail until EOS */
+ if (APR_BUCKET_IS_FLUSH(e)) {
+
+ /* pass the flush bucket across */
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+
+ /* pass what we have down the chain */
+ rv = ap_pass_brigade(f->next, ctx->bb);
+ continue;
+ }
+
+ /* metadata buckets are preserved as is */
+ if (APR_BUCKET_IS_METADATA(e)) {
+ /*
+ * Remove meta data bucket from old brigade and insert into the
+ * new.
+ */
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
+ continue;
+ }
+
+ /* make sure we don't read more than 6000 bytes at a time */
+ apr_brigade_partition(bb, (APR_BUCKET_BUFF_SIZE / 4 * 3), &ee);
+
+ /* size will never be more than 6000 bytes */
+ if (APR_SUCCESS == (rv = apr_bucket_read(e, &data, &size,
+ APR_BLOCK_READ))) {
+
+ /* fill up and write out our overflow buffer if partially used */
+ while (size && ctx->count && ctx->count < sizeof(ctx->overflow)) {
+ ctx->overflow[ctx->count++] = *data++;
+ size--;
+ }
+ if (ctx->count == sizeof(ctx->overflow)) {
+ len = apr_base64_encode_binary(encoded, ctx->overflow,
+ sizeof(ctx->overflow));
+ apr_brigade_write(ctx->bb, NULL, NULL, encoded, len - 1);
+ ctx->count = 0;
+ }
+
+ /* write the main base64 chunk */
+ tail = size % sizeof(ctx->overflow);
+ size -= tail;
+ if (size) {
+ len = apr_base64_encode_binary(buffer,
+ (const unsigned char *) data, size);
+ apr_brigade_write(ctx->bb, NULL, NULL, buffer, len - 1);
+ }
+
+ /* save away any tail in the overflow buffer */
+ if (tail) {
+ memcpy(ctx->overflow, data + size, tail);
+ ctx->count += tail;
+ }
+
+ apr_bucket_delete(e);
+
+ /* pass what we have down the chain */
+ rv = ap_pass_brigade(f->next, ctx->bb);
+ if (rv) {
+ /* should break out of the loop, since our write to the client
+ * failed in some way. */
+ continue;
+ }
+
+ }
+
+ }
+
+ return rv;
+
+}
+
+static const command_rec data_cmds[] = { { NULL } };
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_register_output_filter(DATA_FILTER, data_out_filter, NULL,
+ AP_FTYPE_RESOURCE);
+}
+AP_DECLARE_MODULE(data) = { STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ data_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/filters/mod_data.dsp b/modules/filters/mod_data.dsp
new file mode 100644
index 00000000..e7270312
--- /dev/null
+++ b/modules/filters/mod_data.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_data" - 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_data - Win32 Release
+!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_data.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_data.mak" CFG="mod_data - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_data - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_data - 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_data - 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" /D "HAVE_ZUTIL_H" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_data_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_data.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_data.so" /d LONG_NAME="buffer_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_data.so" /base:@..\..\os\win32\BaseAddr.ref,mod_data.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_data.so" /base:@..\..\os\win32\BaseAddr.ref,mod_data.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_data.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_data - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "HAVE_ZUTIL_H" /Fd"Debug\mod_data_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_data.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_data.so" /d LONG_NAME="buffer_module for Apache"
+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 /out:".\Debug\mod_data.so" /base:@..\..\os\win32\BaseAddr.ref,mod_data.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_data.so" /base:@..\..\os\win32\BaseAddr.ref,mod_data.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_data.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_data - Win32 Release"
+# Name "mod_data - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_data.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c
index 7856e35f..0876cb4e 100644
--- a/modules/filters/mod_deflate.c
+++ b/modules/filters/mod_deflate.c
@@ -157,6 +157,15 @@ static int check_gzip(request_rec *r, apr_table_t *hdrs1, apr_table_t *hdrs2)
}
}
}
+ /*
+ * If we have dealt with the headers above but content_encoding was set
+ * before sync it with the new value in the hdrs table as
+ * r->content_encoding takes precedence later on in the http_header_filter
+ * and hence would destroy what we have just set in the hdrs table.
+ */
+ if (hdrs && r->content_encoding) {
+ r->content_encoding = apr_table_get(hdrs, "Content-Encoding");
+ }
return found;
}
@@ -294,6 +303,7 @@ typedef struct deflate_ctx_t
unsigned char *validation_buffer;
apr_size_t validation_buffer_length;
int inflate_init;
+ int filter_init;
} deflate_ctx;
/* Number of validation bytes (CRC and length) after the compressed data */
@@ -373,6 +383,42 @@ static apr_status_t deflate_ctx_cleanup(void *data)
return APR_SUCCESS;
}
+/* ETag must be unique among the possible representations, so a change
+ * to content-encoding requires a corresponding change to the ETag.
+ * This routine appends -transform (e.g., -gzip) to the entity-tag
+ * value inside the double-quotes if an ETag has already been set
+ * and its value already contains double-quotes. PR 39727
+ */
+static void deflate_check_etag(request_rec *r, const char *transform)
+{
+ const char *etag = apr_table_get(r->headers_out, "ETag");
+ apr_size_t etaglen;
+
+ if ((etag && ((etaglen = strlen(etag)) > 2))) {
+ if (etag[etaglen - 1] == '"') {
+ apr_size_t transformlen = strlen(transform);
+ char *newtag = apr_palloc(r->pool, etaglen + transformlen + 2);
+ char *d = newtag;
+ char *e = d + etaglen - 1;
+ const char *s = etag;
+
+ for (; d < e; ++d, ++s) {
+ *d = *s; /* copy etag to newtag up to last quote */
+ }
+ *d++ = '-'; /* append dash to newtag */
+ s = transform;
+ e = d + transformlen;
+ for (; d < e; ++d, ++s) {
+ *d = *s; /* copy transform to newtag */
+ }
+ *d++ = '"'; /* append quote to newtag */
+ *d = '\0'; /* null terminate newtag */
+
+ apr_table_setn(r->headers_out, "ETag", newtag);
+ }
+ }
+}
+
static apr_status_t deflate_out_filter(ap_filter_t *f,
apr_bucket_brigade *bb)
{
@@ -380,11 +426,13 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
request_rec *r = f->r;
deflate_ctx *ctx = f->ctx;
int zRC;
+ apr_size_t len = 0, blen;
+ const char *data;
deflate_filter_config *c;
/* Do nothing if asked to filter nothing. */
if (APR_BRIGADE_EMPTY(bb)) {
- return ap_pass_brigade(f->next, bb);
+ return APR_SUCCESS;
}
c = ap_get_module_config(r->server->module_config,
@@ -400,22 +448,65 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
char *token;
const char *encoding;
- /* only work on main request/no subrequests */
- if (r->main != NULL) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
+ /* We have checked above that bb is not empty */
+ e = APR_BRIGADE_LAST(bb);
+ if (APR_BUCKET_IS_EOS(e)) {
+ /*
+ * If we already know the size of the response, we can skip
+ * compression on responses smaller than the compression overhead.
+ * However, if we compress, we must initialize deflate_out before
+ * calling ap_pass_brigade() for the first time. Otherwise the
+ * headers will be sent to the client without
+ * "Content-Encoding: gzip".
+ */
+ e = APR_BRIGADE_FIRST(bb);
+ while (1) {
+ apr_status_t rc;
+ if (APR_BUCKET_IS_EOS(e)) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Not compressing very small response of %"
+ APR_SIZE_T_FMT " bytes", len);
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+ if (APR_BUCKET_IS_METADATA(e)) {
+ e = APR_BUCKET_NEXT(e);
+ continue;
+ }
- /* some browsers might have problems, so set no-gzip
- * (with browsermatch) for them
- */
- if (apr_table_get(r->subprocess_env, "no-gzip")) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
+ rc = apr_bucket_read(e, &data, &blen, APR_BLOCK_READ);
+ if (rc != APR_SUCCESS)
+ return rc;
+ len += blen;
+ /* 50 is for Content-Encoding and Vary headers and ETag suffix */
+ if (len > sizeof(gzip_header) + VALIDATION_SIZE + 50)
+ break;
+
+ e = APR_BUCKET_NEXT(e);
+ }
}
- /* We can't operate on Content-Ranges */
- if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
+ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
+
+ /*
+ * Only work on main request, not subrequests,
+ * that are not a 204 response with no content
+ * and are not tagged with the no-gzip env variable
+ * and not a partial response to a Range request.
+ */
+ if ((r->main != NULL) || (r->status == HTTP_NO_CONTENT) ||
+ apr_table_get(r->subprocess_env, "no-gzip") ||
+ apr_table_get(r->headers_out, "Content-Range")
+ ) {
+ if (APLOG_R_IS_LEVEL(r, APLOG_TRACE1)) {
+ const char *reason =
+ (r->main != NULL) ? "subrequest" :
+ (r->status == HTTP_NO_CONTENT) ? "no content" :
+ apr_table_get(r->subprocess_env, "no-gzip") ? "no-gzip" :
+ "content-range";
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Not compressing (%s)", reason);
+ }
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
@@ -429,6 +520,8 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
const char *env_value = apr_table_get(r->subprocess_env,
"gzip-only-text/html");
if ( env_value && (strcmp(env_value,"1") == 0) ) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Not compressing, (gzip-only-text/html)");
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
@@ -465,7 +558,9 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
/* stolen from mod_negotiation: */
if (strcmp(token, "identity") && strcmp(token, "7bit") &&
strcmp(token, "8bit") && strcmp(token, "binary")) {
-
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Not compressing (content-encoding already "
+ " set: %s)", token);
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
@@ -501,7 +596,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
/* skip parameters, XXX: ;q=foo evaluation? */
while (*accepts == ';') {
++accepts;
- token = ap_get_token(r->pool, &accepts, 1);
+ ap_get_token(r->pool, &accepts, 1);
}
/* retrieve next token */
@@ -513,53 +608,62 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
/* No acceptable token found. */
if (token == NULL || token[0] == '\0') {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Not compressing (no Accept-Encoding: gzip)");
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
}
-
- /* For a 304 or 204 response there is no entity included in
- * the response and hence nothing to deflate. */
- if (r->status == HTTP_NOT_MODIFIED || r->status == HTTP_NO_CONTENT) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Forcing compression (force-gzip set)");
}
- /* We're cool with filtering this. */
- ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
- ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
- ctx->buffer = apr_palloc(r->pool, c->bufferSize);
- ctx->libz_end_func = deflateEnd;
+ /* At this point we have decided to filter the content. Let's try to
+ * to initialize zlib (except for 304 responses, where we will only
+ * send out the headers).
+ */
- zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
- c->windowSize, c->memlevel,
- Z_DEFAULT_STRATEGY);
+ if (r->status != HTTP_NOT_MODIFIED) {
+ ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
+ ctx->buffer = apr_palloc(r->pool, c->bufferSize);
+ ctx->libz_end_func = deflateEnd;
- if (zRC != Z_OK) {
- deflateEnd(&ctx->stream);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "unable to init Zlib: "
- "deflateInit2 returned %d: URL %s",
- zRC, r->uri);
+ zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
+ c->windowSize, c->memlevel,
+ Z_DEFAULT_STRATEGY);
+
+ if (zRC != Z_OK) {
+ deflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01383)
+ "unable to init Zlib: "
+ "deflateInit2 returned %d: URL %s",
+ zRC, r->uri);
+ /*
+ * Remove ourselves as it does not make sense to return:
+ * We are not able to init libz and pass data down the chain
+ * uncompressed.
+ */
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
/*
- * Remove ourselves as it does not make sense to return:
- * We are not able to init libz and pass data down the chain
- * uncompressed.
+ * Register a cleanup function to ensure that we cleanup the internal
+ * libz resources.
*/
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
+ apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
+ apr_pool_cleanup_null);
+
+ /* Set the filter init flag so subsequent invocations know we are
+ * active.
+ */
+ ctx->filter_init = 1;
}
+
/*
- * Register a cleanup function to ensure that we cleanup the internal
- * libz resources.
+ * Zlib initialization worked, so we can now change the important
+ * content metadata before sending the response out.
*/
- apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
- apr_pool_cleanup_null);
-
- /* add immortal gzip header */
- e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
- f->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
/* If the entire Content-Encoding is "identity", we can replace it. */
if (!encoding || !strcasecmp(encoding, "identity")) {
@@ -568,19 +672,39 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
else {
apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");
}
+ /* Fix r->content_encoding if it was set before */
+ if (r->content_encoding) {
+ r->content_encoding = apr_table_get(r->headers_out,
+ "Content-Encoding");
+ }
apr_table_unset(r->headers_out, "Content-Length");
apr_table_unset(r->headers_out, "Content-MD5");
+ deflate_check_etag(r, "gzip");
+
+ /* For a 304 response, only change the headers */
+ if (r->status == HTTP_NOT_MODIFIED) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ /* add immortal gzip header */
+ e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
+ f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
/* initialize deflate output buffer */
ctx->stream.next_out = ctx->buffer;
ctx->stream.avail_out = c->bufferSize;
+ } else if (!ctx->filter_init) {
+ /* Hmm. We've run through the filter init before as we have a ctx,
+ * but we never initialized. We probably have a dangling ref. Bail.
+ */
+ return ap_pass_brigade(f->next, bb);
}
while (!APR_BRIGADE_EMPTY(bb))
{
- const char *data;
apr_bucket *b;
- apr_size_t len;
/*
* Optimization: If we are a HEAD request and bytes_sent is not zero
@@ -612,7 +736,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
b = apr_bucket_pool_create(buf, VALIDATION_SIZE, r->pool,
f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01384)
"Zlib: Compressed %ld to %ld : URL %s",
ctx->stream.total_in, ctx->stream.total_out, r->uri);
@@ -664,6 +788,9 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
Z_SYNC_FLUSH, NO_UPDATE_CRC);
if (zRC != Z_OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01385)
+ "Zlib error %d flushing zlib output buffer (%s)",
+ zRC, ctx->stream.msg);
return APR_EGENERAL;
}
@@ -720,6 +847,9 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
if (zRC != Z_OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01386)
+ "Zlib error %d deflating data (%s)", zRC,
+ ctx->stream.msg);
return APR_EGENERAL;
}
}
@@ -803,11 +933,14 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
if (len != 10 ||
deflate_hdr[0] != deflate_magic[0] ||
deflate_hdr[1] != deflate_magic[1]) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01387) "Zlib: Invalid header");
return APR_EGENERAL;
}
/* We can't handle flags for now. */
if (deflate_hdr[3] != 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01388)
+ "Zlib: Unsupported flags %02x", (int)deflate_hdr[3]);
return APR_EGENERAL;
}
@@ -816,7 +949,7 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
if (zRC != Z_OK) {
f->ctx = NULL;
inflateEnd(&ctx->stream);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01389)
"unable to init Zlib: "
"inflateInit2 returned %d: URL %s",
zRC, r->uri);
@@ -850,6 +983,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
/* If we actually see the EOS, that means we screwed up! */
if (APR_BUCKET_IS_EOS(bkt)) {
inflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01390)
+ "Encountered EOS bucket in inflate filter (bug?)");
return APR_EGENERAL;
}
@@ -858,6 +993,9 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
if (zRC != Z_OK) {
inflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01391)
+ "Zlib error %d inflating data (%s)", zRC,
+ ctx->stream.msg);
return APR_EGENERAL;
}
@@ -906,13 +1044,16 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
if (zRC != Z_OK) {
inflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01392)
+ "Zlib error %d inflating data (%s)", zRC,
+ ctx->stream.msg);
return APR_EGENERAL;
}
}
if (zRC == Z_STREAM_END) {
apr_bucket *tmp_heap, *eos;
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01393)
"Zlib: Inflated %ld to %ld : URL %s",
ctx->stream.total_in, ctx->stream.total_out,
r->uri);
@@ -931,12 +1072,18 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
compCRC = getLong(ctx->stream.next_in);
if (ctx->crc != compCRC) {
inflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01394)
+ "Zlib: CRC error inflating data");
return APR_EGENERAL;
}
ctx->stream.next_in += 4;
compLen = getLong(ctx->stream.next_in);
if (ctx->stream.total_out != compLen) {
inflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01395)
+ "Zlib: Length %ld of inflated data does "
+ "not match expected value %ld",
+ ctx->stream.total_out, compLen);
return APR_EGENERAL;
}
}
@@ -944,6 +1091,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
/* FIXME: We need to grab the 8 verification bytes
* from the wire! */
inflateEnd(&ctx->stream);
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01396)
+ "Verification data not available (bug?)");
return APR_EGENERAL;
}
@@ -977,14 +1126,13 @@ static apr_status_t deflate_in_filter(ap_filter_t *f,
}
if (!APR_BRIGADE_EMPTY(ctx->proc_bb)) {
- apr_bucket_brigade *newbb;
-
- /* May return APR_INCOMPLETE which is fine by us. */
- apr_brigade_partition(ctx->proc_bb, readbytes, &bkt);
-
- newbb = apr_brigade_split(ctx->proc_bb, bkt);
- APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
- APR_BRIGADE_CONCAT(ctx->proc_bb, newbb);
+ if (apr_brigade_partition(ctx->proc_bb, readbytes, &bkt) == APR_INCOMPLETE) {
+ APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
+ }
+ else {
+ APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
+ apr_brigade_split_ex(bb, bkt, ctx->proc_bb);
+ }
}
return APR_SUCCESS;
@@ -1006,36 +1154,38 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
/* Do nothing if asked to filter nothing. */
if (APR_BRIGADE_EMPTY(bb)) {
- return ap_pass_brigade(f->next, bb);
+ return APR_SUCCESS;
}
c = ap_get_module_config(r->server->module_config, &deflate_module);
if (!ctx) {
- /* only work on main request/no subrequests */
- if (!ap_is_initial_req(r)) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
-
- /* We can't operate on Content-Ranges */
- if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
+ /*
+ * Only work on main request, not subrequests,
+ * that are not a 204 response with no content
+ * and not a partial response to a Range request,
+ * and only when Content-Encoding ends in gzip.
+ */
+ if (!ap_is_initial_req(r) || (r->status == HTTP_NO_CONTENT) ||
+ (apr_table_get(r->headers_out, "Content-Range") != NULL) ||
+ (check_gzip(r, r->headers_out, r->err_headers_out) == 0)
+ ) {
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
/*
- * Let's see what our current Content-Encoding is.
- * Only inflate if gzipped.
+ * At this point we have decided to filter the content, so change
+ * important content metadata before sending any response out.
+ * Content-Encoding was already reset by the check_gzip() call.
*/
- if (check_gzip(r, r->headers_out, r->err_headers_out) == 0) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, bb);
- }
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Content-MD5");
+ deflate_check_etag(r, "gunzip");
- /* No need to inflate HEAD or 204/304 */
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
+ /* For a 304 response, only change the headers */
+ if (r->status == HTTP_NOT_MODIFIED) {
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
}
@@ -1052,7 +1202,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
if (zRC != Z_OK) {
f->ctx = NULL;
inflateEnd(&ctx->stream);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01397)
"unable to init Zlib: "
"inflateInit2 returned %d: URL %s",
zRC, r->uri);
@@ -1072,10 +1222,6 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
apr_pool_cleanup_null);
- /* these are unlikely to be set anyway, but ... */
- apr_table_unset(r->headers_out, "Content-Length");
- apr_table_unset(r->headers_out, "Content-MD5");
-
/* initialize inflate output buffer */
ctx->stream.next_out = ctx->buffer;
ctx->stream.avail_out = c->bufferSize;
@@ -1110,7 +1256,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
*/
flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate, Z_SYNC_FLUSH,
UPDATE_CRC);
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01398)
"Zlib: Inflated %ld to %ld : URL %s",
ctx->stream.total_in, ctx->stream.total_out, r->uri);
@@ -1118,20 +1264,20 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
unsigned long compCRC, compLen;
compCRC = getLong(ctx->validation_buffer);
if (ctx->crc != compCRC) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01399)
"Zlib: Checksum of inflated stream invalid");
return APR_EGENERAL;
}
ctx->validation_buffer += VALIDATION_SIZE / 2;
compLen = getLong(ctx->validation_buffer);
if (ctx->stream.total_out != compLen) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01400)
"Zlib: Length of inflated stream invalid");
return APR_EGENERAL;
}
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01401)
"Zlib: Validation bytes not present");
return APR_EGENERAL;
}
@@ -1158,6 +1304,9 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate,
Z_SYNC_FLUSH, UPDATE_CRC);
if (zRC != Z_OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01402)
+ "Zlib error %d flushing inflate buffer (%s)",
+ zRC, ctx->stream.msg);
return APR_EGENERAL;
}
@@ -1187,7 +1336,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
/* first bucket contains zlib header */
if (!ctx->inflate_init++) {
if (len < 10) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01403)
"Insufficient data for inflate");
return APR_EGENERAL;
}
@@ -1195,7 +1344,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
zlib_method = data[2];
zlib_flags = data[3];
if (zlib_method != Z_DEFLATED) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01404)
"inflate: data not deflated!");
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb);
@@ -1203,7 +1352,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
if (data[0] != deflate_magic[0] ||
data[1] != deflate_magic[1] ||
(zlib_flags & RESERVED) != 0) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01405)
"inflate: bad header");
return APR_EGENERAL ;
}
@@ -1215,7 +1364,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
bytes += ((unsigned int)(data[1])) << 8;
bytes += 2;
if (len < bytes) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01406)
"inflate: extra field too big (not "
"supported)");
return APR_EGENERAL;
@@ -1253,7 +1402,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
ctx->validation_buffer_length += copy_size;
}
if (ctx->stream.avail_in) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01407)
"Zlib: %d bytes of garbage at the end of "
"compressed stream.", ctx->stream.avail_in);
/*
@@ -1267,8 +1416,6 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
}
}
- zRC = Z_OK;
-
while (ctx->stream.avail_in != 0) {
if (ctx->stream.avail_out == 0) {
@@ -1299,7 +1446,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
VALIDATION_SIZE);
if (ctx->stream.avail_in > VALIDATION_SIZE) {
ctx->validation_buffer_length = VALIDATION_SIZE;
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01408)
"Zlib: %d bytes of garbage at the end of "
"compressed stream.",
ctx->stream.avail_in - VALIDATION_SIZE);
@@ -1313,6 +1460,9 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
}
if (zRC != Z_OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01409)
+ "Zlib error %d inflating data (%s)", zRC,
+ ctx->stream.msg);
return APR_EGENERAL;
}
}
@@ -1349,7 +1499,7 @@ static const command_rec deflate_filter_cmds[] = {
{NULL}
};
-module AP_MODULE_DECLARE_DATA deflate_module = {
+AP_DECLARE_MODULE(deflate) = {
STANDARD20_MODULE_STUFF,
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
diff --git a/modules/filters/mod_deflate.dep b/modules/filters/mod_deflate.dep
deleted file mode 100644
index 75fc104e..00000000
--- a/modules/filters/mod_deflate.dep
+++ /dev/null
@@ -1,28 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_deflate.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_deflate.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.h"\
- "..\..\include\http_config.h"\
- "..\..\include\http_log.h"\
- "..\..\include\http_request.h"\
- "..\..\include\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_filter.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_lib.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
- "..\..\srclib\zlib\zconf.h"\
- "..\..\srclib\zlib\zlib.h"\
-
diff --git a/modules/filters/mod_deflate.mak b/modules/filters/mod_deflate.mak
deleted file mode 100644
index 4549eabb..00000000
--- a/modules/filters/mod_deflate.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_deflate.dsp
-!IF "$(CFG)" == ""
-CFG=mod_deflate - Win32 Release
-!MESSAGE No configuration specified. Defaulting to mod_deflate - Win32 Release.
-!ENDIF
-
-!IF "$(CFG)" != "mod_deflate - Win32 Release" && "$(CFG)" != "mod_deflate - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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_deflate.mak" CFG="mod_deflate - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_deflate - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_deflate - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_deflate - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_deflate.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_deflate.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_deflate.obj"
- -@erase "$(INTDIR)\mod_deflate.res"
- -@erase "$(INTDIR)\mod_deflate_src.idb"
- -@erase "$(INTDIR)\mod_deflate_src.pdb"
- -@erase "$(OUTDIR)\mod_deflate.exp"
- -@erase "$(OUTDIR)\mod_deflate.lib"
- -@erase "$(OUTDIR)\mod_deflate.pdb"
- -@erase "$(OUTDIR)\mod_deflate.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/zlib" /D "NDEBUG" /D "ZLIB_DLL" /D "HAVE_ZUTIL_H" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_deflate_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_deflate.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_deflate.so" /d LONG_NAME="deflate_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_deflate.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib zdll.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_deflate.pdb" /debug /out:"$(OUTDIR)\mod_deflate.so" /implib:"$(OUTDIR)\mod_deflate.lib" /libpath:"../../srclib/zlib" /base:@..\..\os\win32\BaseAddr.ref,mod_deflate.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_deflate.obj" \
- "$(INTDIR)\mod_deflate.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_deflate.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_deflate.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_deflate.so"
- if exist .\Release\mod_deflate.so.manifest mt.exe -manifest .\Release\mod_deflate.so.manifest -outputresource:.\Release\mod_deflate.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_deflate - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_deflate.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_deflate.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_deflate.obj"
- -@erase "$(INTDIR)\mod_deflate.res"
- -@erase "$(INTDIR)\mod_deflate_src.idb"
- -@erase "$(INTDIR)\mod_deflate_src.pdb"
- -@erase "$(OUTDIR)\mod_deflate.exp"
- -@erase "$(OUTDIR)\mod_deflate.lib"
- -@erase "$(OUTDIR)\mod_deflate.pdb"
- -@erase "$(OUTDIR)\mod_deflate.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/zlib" /D "_DEBUG" /D "ZLIB_DLL" /D "HAVE_ZUTIL_H" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_deflate_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_deflate.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_deflate.so" /d LONG_NAME="deflate_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_deflate.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib zdll.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_deflate.pdb" /debug /out:"$(OUTDIR)\mod_deflate.so" /implib:"$(OUTDIR)\mod_deflate.lib" /libpath:"../../srclib/zlib" /base:@..\..\os\win32\BaseAddr.ref,mod_deflate.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_deflate.obj" \
- "$(INTDIR)\mod_deflate.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_deflate.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_deflate.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_deflate.so"
- if exist .\Debug\mod_deflate.so.manifest mt.exe -manifest .\Debug\mod_deflate.so.manifest -outputresource:.\Debug\mod_deflate.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_deflate.dep")
-!INCLUDE "mod_deflate.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_deflate.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_deflate - Win32 Release" || "$(CFG)" == "mod_deflate - Win32 Debug"
-
-!IF "$(CFG)" == "mod_deflate - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_deflate - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_deflate - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_deflate - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_deflate - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_deflate - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_deflate - Win32 Release"
-
-
-"$(INTDIR)\mod_deflate.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_deflate.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_deflate.so" /d LONG_NAME="deflate_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_deflate - Win32 Debug"
-
-
-"$(INTDIR)\mod_deflate.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_deflate.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_deflate.so" /d LONG_NAME="deflate_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_deflate.c
-
-"$(INTDIR)\mod_deflate.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_ext_filter.c b/modules/filters/mod_ext_filter.c
index fe922716..3412c21d 100644
--- a/modules/filters/mod_ext_filter.c
+++ b/modules/filters/mod_ext_filter.c
@@ -22,7 +22,7 @@
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
-#define CORE_PRIVATE
+
#include "http_core.h"
#include "apr_buckets.h"
#include "util_filter.h"
@@ -56,7 +56,6 @@ typedef struct ef_filter_t {
} ef_filter_t;
typedef struct ef_dir_t {
- int debug;
int log_stderr;
int onfail;
} ef_dir_t;
@@ -81,16 +80,12 @@ static apr_status_t ef_input_filter(ap_filter_t *, apr_bucket_brigade *,
ap_input_mode_t, apr_read_type_e,
apr_off_t);
-#define DBGLVL_SHOWOPTIONS 1
-#define DBGLVL_GORY 9
-
#define ERRFN_USERDATA_KEY "EXTFILTCHILDERRFN"
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;
dc->onfail = -1;
@@ -112,13 +107,6 @@ 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;
}
@@ -141,10 +129,7 @@ static const char *add_options(cmd_parms *cmd, void *in_dc,
{
ef_dir_t *dc = in_dc;
- if (!strncasecmp(arg, "DebugLevel=", 11)) {
- dc->debug = atoi(arg + 11);
- }
- else if (!strcasecmp(arg, "LogStderr")) {
+ if (!strcasecmp(arg, "LogStderr")) {
dc->log_stderr = 1;
}
else if (!strcasecmp(arg, "NoLogStderr")) {
@@ -354,7 +339,7 @@ static const command_rec cmds[] =
add_options,
NULL,
ACCESS_CONF, /* same as SetInputFilter/SetOutputFilter */
- "valid options: DebugLevel=n, LogStderr, NoLogStderr"),
+ "valid options: LogStderr, NoLogStderr"),
AP_INIT_RAW_ARGS("ExtFilterDefine",
define_filter,
NULL,
@@ -380,8 +365,7 @@ static apr_status_t set_resource_limits(request_rec *r,
#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);
+ (core_dir_config *)ap_get_core_module_config(r->per_dir_config);
apr_status_t rv;
#ifdef RLIMIT_CPU
@@ -422,7 +406,7 @@ static void child_errfn(apr_pool_t *pool, apr_status_t err, const char *descript
apr_file_printf(stderr_log,
"[%s] [client %s] mod_ext_filter (%d)%s: %s\n",
time_str,
- r->connection->remote_ip,
+ r->useragent_ip,
err,
apr_strerror(err, errbuf, sizeof(errbuf)),
description);
@@ -493,7 +477,7 @@ static apr_status_t init_ext_filter_process(ap_filter_t *f)
ctx->procattr,
ctx->p);
if (rc != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r, APLOGNO(01458)
"couldn't create child process to run `%s'",
ctx->filter->command);
return rc;
@@ -537,8 +521,6 @@ static apr_status_t init_ext_filter_process(ap_filter_t *f)
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 ?
@@ -549,9 +531,9 @@ static const char *get_cfg_string(ef_dir_t *dc, ef_filter_t *filter, apr_pool_t
"(unchanged)" : filter->outtype;
return apr_psprintf(p,
- "ExtFilterOptions %s %s %s ExtFilterInType %s "
+ "ExtFilterOptions %s %s ExtFilterInType %s "
"ExtFilterOuttype %s",
- debug_str, log_stderr_str, preserve_content_length_str,
+ log_stderr_str, preserve_content_length_str,
intype_str, outtype_str);
}
@@ -583,7 +565,7 @@ static apr_status_t init_filter_instance(ap_filter_t *f)
/* look for the user-defined filter */
ctx->filter = find_filter_def(f->r->server, f->frec->name);
if (!ctx->filter) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01459)
"couldn't find definition of filter '%s'",
f->frec->name);
return APR_EINVAL;
@@ -638,8 +620,8 @@ static apr_status_t init_filter_instance(ap_filter_t *f)
}
}
- if (dc->debug >= DBGLVL_SHOWOPTIONS) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r,
+ if (APLOGrtrace1(f->r)) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r,
"%sfiltering `%s' of type `%s' through `%s', cfg %s",
ctx->noop ? "NOT " : "",
f->r->uri ? f->r->uri : f->r->filename,
@@ -662,23 +644,20 @@ static apr_status_t drain_available_output(ap_filter_t *f,
request_rec *r = f->r;
conn_rec *c = r->connection;
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 *b;
while (1) {
+ int lvl = APLOG_TRACE5;
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, r,
- "apr_file_read(child output), len %" APR_SIZE_T_FMT,
- !rv ? len : -1);
- }
+ rv = apr_file_read(ctx->proc->out, buf, &len);
+ if (rv && !APR_STATUS_IS_EAGAIN(rv))
+ lvl = APLOG_DEBUG;
+ ap_log_rerror(APLOG_MARK, lvl, rv, r, APLOGNO(01460)
+ "apr_file_read(child output), len %" APR_SIZE_T_FMT,
+ !rv ? len : -1);
if (rv != APR_SUCCESS) {
return rv;
}
@@ -696,7 +675,6 @@ static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data,
apr_size_t len, apr_bucket_brigade *bb)
{
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;
@@ -708,7 +686,7 @@ static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data,
&tmplen);
bytes_written += tmplen;
if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01461)
"apr_file_write(child input), len %" APR_SIZE_T_FMT,
tmplen);
return rv;
@@ -726,23 +704,20 @@ static apr_status_t pass_data_to_filter(ap_filter_t *f, const char *data,
rv = apr_pollset_poll(ctx->pollset, f->r->server->timeout,
&num_events, &pdesc);
- if (rv || dc->debug >= DBGLVL_GORY) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG,
- rv, f->r, "apr_pollset_poll()");
- }
if (rv != APR_SUCCESS && !APR_STATUS_IS_EINTR(rv)) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, f->r, APLOGNO(01462)
+ "apr_pollset_poll()");
/* some error such as APR_TIMEUP */
return rv;
}
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE6, rv, f->r,
+ "apr_pollset_poll()");
#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,
- 0, f->r, "apr_sleep()");
- }
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE6, 0, f->r, "apr_sleep()");
#endif /* APR_FILES_AS_SOCKETS */
}
else if (rv != APR_SUCCESS) {
@@ -765,7 +740,6 @@ static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
conn_rec *c = r->connection;
ef_ctx_t *ctx = f->ctx;
apr_bucket *b;
- ef_dir_t *dc;
apr_size_t len;
const char *data;
apr_status_t rv;
@@ -773,7 +747,6 @@ static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
apr_bucket *eos = NULL;
apr_bucket_brigade *bb_tmp;
- dc = ctx->dc;
bb_tmp = apr_brigade_create(r->pool, c->bucket_alloc);
for (b = APR_BRIGADE_FIRST(bb);
@@ -787,7 +760,7 @@ static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_bucket_read()");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01463) "apr_bucket_read()");
return rv;
}
@@ -808,7 +781,7 @@ static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
* 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, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01464)
"apr_file_close(child input)");
return rv;
}
@@ -818,23 +791,21 @@ static int ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
rv = apr_file_pipe_timeout_set(ctx->proc->out,
r->server->timeout);
if (rv) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01465)
"apr_file_pipe_timeout_set(child output)");
return rv;
}
}
do {
+ int lvl = APLOG_TRACE6;
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, r,
- "apr_file_read(child output), len %" APR_SIZE_T_FMT,
- !rv ? len : -1);
- }
+ rv = apr_file_read(ctx->proc->out, buf, &len);
+ if (rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv))
+ lvl = APLOG_ERR;
+ ap_log_rerror(APLOG_MARK, lvl, rv, r, APLOGNO(01466)
+ "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 */
@@ -870,7 +841,7 @@ static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
if (!ctx) {
if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
ctx = f->ctx;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01467)
"can't initialise output filter %s: %s",
f->frec->name,
(ctx->dc->onfail == 1) ? "removing" : "aborting");
@@ -902,12 +873,12 @@ static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
rv = ef_unified_filter(f, bb);
if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01468)
"ef_unified_filter() failed");
}
if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(01469)
"ap_pass_brigade() failed");
}
return rv;
@@ -923,7 +894,7 @@ static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
if (!ctx) {
if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
ctx = f->ctx;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01470)
"can't initialise input filter %s: %s",
f->frec->name,
(ctx->dc->onfail == 1) ? "removing" : "aborting");
@@ -953,7 +924,7 @@ static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
return rv;
}
-module AP_MODULE_DECLARE_DATA ext_filter_module =
+AP_DECLARE_MODULE(ext_filter) =
{
STANDARD20_MODULE_STUFF,
create_ef_dir_conf,
diff --git a/modules/filters/mod_ext_filter.dep b/modules/filters/mod_ext_filter.dep
deleted file mode 100644
index 29ef590c..00000000
--- a/modules/filters/mod_ext_filter.dep
+++ /dev/null
@@ -1,32 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_ext_filter.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_ext_filter.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.h"\
- "..\..\include\http_config.h"\
- "..\..\include\http_core.h"\
- "..\..\include\http_log.h"\
- "..\..\include\http_protocol.h"\
- "..\..\include\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_filter.h"\
- "..\..\include\util_script.h"\
- "..\..\include\util_time.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_hash.h"\
- "..\..\srclib\apr\include\apr_lib.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_portable.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
-
diff --git a/modules/filters/mod_ext_filter.mak b/modules/filters/mod_ext_filter.mak
deleted file mode 100644
index 08faf1d2..00000000
--- a/modules/filters/mod_ext_filter.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_ext_filter.dsp
-!IF "$(CFG)" == ""
-CFG=mod_ext_filter - Win32 Release
-!MESSAGE No configuration specified. Defaulting to mod_ext_filter - Win32 Release.
-!ENDIF
-
-!IF "$(CFG)" != "mod_ext_filter - Win32 Release" && "$(CFG)" != "mod_ext_filter - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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_ext_filter.mak" CFG="mod_ext_filter - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_ext_filter - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_ext_filter - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_ext_filter - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_ext_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_ext_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_ext_filter.obj"
- -@erase "$(INTDIR)\mod_ext_filter.res"
- -@erase "$(INTDIR)\mod_ext_filter_src.idb"
- -@erase "$(INTDIR)\mod_ext_filter_src.pdb"
- -@erase "$(OUTDIR)\mod_ext_filter.exp"
- -@erase "$(OUTDIR)\mod_ext_filter.lib"
- -@erase "$(OUTDIR)\mod_ext_filter.pdb"
- -@erase "$(OUTDIR)\mod_ext_filter.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_ext_filter_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_ext_filter.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_ext_filter.so" /d LONG_NAME="ext_filter_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_ext_filter.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_ext_filter.pdb" /debug /out:"$(OUTDIR)\mod_ext_filter.so" /implib:"$(OUTDIR)\mod_ext_filter.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_ext_filter.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_ext_filter.obj" \
- "$(INTDIR)\mod_ext_filter.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_ext_filter.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_ext_filter.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_ext_filter.so"
- if exist .\Release\mod_ext_filter.so.manifest mt.exe -manifest .\Release\mod_ext_filter.so.manifest -outputresource:.\Release\mod_ext_filter.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_ext_filter - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_ext_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_ext_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_ext_filter.obj"
- -@erase "$(INTDIR)\mod_ext_filter.res"
- -@erase "$(INTDIR)\mod_ext_filter_src.idb"
- -@erase "$(INTDIR)\mod_ext_filter_src.pdb"
- -@erase "$(OUTDIR)\mod_ext_filter.exp"
- -@erase "$(OUTDIR)\mod_ext_filter.lib"
- -@erase "$(OUTDIR)\mod_ext_filter.pdb"
- -@erase "$(OUTDIR)\mod_ext_filter.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_ext_filter_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_ext_filter.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_ext_filter.so" /d LONG_NAME="ext_filter_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_ext_filter.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_ext_filter.pdb" /debug /out:"$(OUTDIR)\mod_ext_filter.so" /implib:"$(OUTDIR)\mod_ext_filter.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_ext_filter.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_ext_filter.obj" \
- "$(INTDIR)\mod_ext_filter.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_ext_filter.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_ext_filter.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_ext_filter.so"
- if exist .\Debug\mod_ext_filter.so.manifest mt.exe -manifest .\Debug\mod_ext_filter.so.manifest -outputresource:.\Debug\mod_ext_filter.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_ext_filter.dep")
-!INCLUDE "mod_ext_filter.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_ext_filter.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_ext_filter - Win32 Release" || "$(CFG)" == "mod_ext_filter - Win32 Debug"
-
-!IF "$(CFG)" == "mod_ext_filter - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_ext_filter - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_ext_filter - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_ext_filter - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_ext_filter - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_ext_filter - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_ext_filter - Win32 Release"
-
-
-"$(INTDIR)\mod_ext_filter.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_ext_filter.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_ext_filter.so" /d LONG_NAME="ext_filter_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_ext_filter - Win32 Debug"
-
-
-"$(INTDIR)\mod_ext_filter.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_ext_filter.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_ext_filter.so" /d LONG_NAME="ext_filter_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_ext_filter.c
-
-"$(INTDIR)\mod_ext_filter.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_filter.c b/modules/filters/mod_filter.c
index ad7aba3d..32d8bd33 100644
--- a/modules/filters/mod_filter.c
+++ b/modules/filters/mod_filter.c
@@ -24,6 +24,7 @@
#include "http_request.h"
#include "http_log.h"
#include "util_filter.h"
+#include "ap_expr.h"
module AP_MODULE_DECLARE_DATA filter_module;
@@ -35,46 +36,14 @@ module AP_MODULE_DECLARE_DATA filter_module;
* (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;
+ ap_expr_info_t *expr;
+ const char **types;
/** 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 */
@@ -114,12 +83,12 @@ static void filter_trace(conn_rec *c, int debug, const char *fname,
case 0: /* normal, operational use */
return;
case 1: /* mod_diagnostics level */
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s", fname);
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01375) "%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,
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01376)
"%s: type: %s, length: %" APR_SIZE_T_FMT,
fname, b->type->name ? b->type->name : "(unknown)",
b->length);
@@ -138,14 +107,14 @@ static int filter_init(ap_filter_t *f)
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 == filter_init) {
- ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c,
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(01377)
"Chaining of FilterProviders not supported");
return HTTP_INTERNAL_SERVER_ERROR;
}
else 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,
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(01378)
"filter_init for %s failed", p->frec->name);
return err; /* if anyone errors out here, so do we */
}
@@ -162,109 +131,55 @@ static int filter_init(ap_filter_t *f)
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;
+ int match = 0;
+ const char *err = NULL;
request_rec *r = f->r;
harness_ctx *ctx = f->ctx;
provider_ctx *pctx;
+#ifndef NO_PROTOCOL
+ unsigned int proto_flags;
mod_filter_ctx *rctx = ap_get_module_config(r->request_config,
&filter_module);
+#endif
/* 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:
- /* Try r->headers_out first, fall back on err_headers_out. */
- str = apr_table_get(r->headers_out, provider->value);
- if (str) {
- break;
+ if (provider->expr) {
+ match = ap_expr_exec(r, provider->expr, &err);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01379)
+ "Error evaluating filter dispatch condition: %s",
+ err);
+ match = 0;
}
- str = apr_table_get(r->err_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) {
- match = 0;
- }
- /* we can't check for NULL in provider as that kills integer 0
- * so we have to test each string/regexp case in the switch
- */
- else {
- 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;
- /* Integer comparisons should be [var] OP [match]
- * We need to set match = 0 if the condition fails
- */
- case INT_LT:
- if (atoi(str) >= provider->match.number) {
- match = 0;
- }
- break;
- case INT_LE:
- if (atoi(str) > provider->match.number) {
- match = 0;
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "Expression condition for '%s' %s",
+ provider->frec->name,
+ match ? "matched" : "did not match");
+ }
+ else if (r->content_type) {
+ const char **type = provider->types;
+ size_t len = strcspn(r->content_type, "; \t");
+ AP_DEBUG_ASSERT(type != NULL);
+ while (*type) {
+ /* Handle 'content-type;charset=...' correctly */
+ if (strncmp(*type, r->content_type, len) == 0
+ && (*type)[len] == '\0') {
+ match = 1;
+ break;
}
- 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;
+ type++;
}
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "Content-Type condition for '%s' %s",
+ provider->frec->name,
+ match ? "matched" : "did not match");
}
- if (match != provider->not) {
+ if (match) {
/* condition matches this provider */
#ifndef NO_PROTOCOL
/* check protocol
@@ -289,9 +204,10 @@ static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
}
if (proto_flags & AP_FILTER_PROTO_TRANSFORM) {
- str = apr_table_get(r->headers_out, "Cache-Control");
+ const char *str = apr_table_get(r->headers_out,
+ "Cache-Control");
if (str) {
- str1 = apr_pstrdup(r->pool, str);
+ char *str1 = apr_pstrdup(r->pool, str);
ap_str_tolower(str1);
if (strstr(str1, "no-transform")) {
/* can't use this provider; try next */
@@ -346,8 +262,10 @@ static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter)
static apr_status_t filter_harness(ap_filter_t *f, apr_bucket_brigade *bb)
{
apr_status_t ret;
+#ifndef NO_PROTOCOL
const char *cachecontrol;
char *str;
+#endif
harness_ctx *ctx = f->ctx;
ap_filter_rec_t *filter = f->frec;
@@ -501,27 +419,17 @@ static const char *filter_declare(cmd_parms *cmd, void *CFG, const char *fname,
return NULL;
}
-static const char *filter_provider(cmd_parms *cmd, void *CFG, const char *args)
+static const char *add_filter(cmd_parms *cmd, void *CFG,
+ const char *fname, const char *pname,
+ const char *expr, const char **types)
{
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" ;
- }
+ ap_expr_info_t *node;
+ const char *err = NULL;
/* fname has been declared with DeclareFilter, so we can look it up */
frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
@@ -544,118 +452,32 @@ static const char *filter_provider(cmd_parms *cmd, void *CFG, const char *args)
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;
+ if (expr) {
+ node = ap_expr_parse_cmd(cmd, expr, 0, &err, NULL);
+ if (err) {
+ return apr_pstrcat(cmd->pool,
+ "Error parsing FilterProvider expression:", err,
+ NULL);
+ }
+ provider->expr = node;
}
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_strrchr_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);
- if (provider->match.regex == NULL) {
- return "Bad regexp";
- }
- 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->types = types;
}
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)
- && !strcasecmp(str, "content-type")) {
- provider->dispatch = CONTENT_TYPE;
- }
- provider->value = str;
-
return NULL;
}
+static const char *filter_provider(cmd_parms *cmd, void *CFG,
+ const char *fname, const char *pname,
+ const char *expr)
+{
+ return add_filter(cmd, CFG, fname, pname, expr, NULL);
+}
+
static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg)
{
mod_filter_chain *p;
@@ -698,8 +520,8 @@ static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg)
break;
case '!': /* Empty the chain */
- /** IG: Add a NULL provider to the beginning so that
- * we can ensure that we'll empty everything before
+ /** IG: Add a NULL provider to the beginning so that
+ * we can ensure that we'll empty everything before
* this when doing config merges later */
p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain));
p->fname = NULL;
@@ -731,6 +553,56 @@ static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg)
return NULL;
}
+static const char *filter_bytype1(cmd_parms *cmd, void *CFG,
+ const char *pname, const char **types)
+{
+ const char *rv;
+ const char *fname;
+ int seen_name = 0;
+ mod_filter_cfg *cfg = CFG;
+
+ /* construct fname from name */
+ fname = apr_pstrcat(cmd->pool, "BYTYPE:", pname, NULL);
+
+ /* check whether this is already registered, in which case
+ * it's already in the filter chain
+ */
+ if (apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING)) {
+ seen_name = 1;
+ }
+
+ rv = add_filter(cmd, CFG, fname, pname, NULL, types);
+
+ /* If it's the first time through, add to filterchain */
+ if (rv == NULL && !seen_name) {
+ rv = filter_chain(cmd, CFG, fname);
+ }
+ return rv;
+}
+
+static const char *filter_bytype(cmd_parms *cmd, void *CFG,
+ int argc, char *const argv[])
+{
+ /* back compatibility, need to parse multiple components in filter name */
+ char *pname;
+ char *strtok_state = NULL;
+ char *name;
+ const char **types;
+ const char *rv = NULL;
+ if (argc < 2)
+ return "AddOutputFilterByType requires at least two arguments";
+ name = apr_pstrdup(cmd->temp_pool, argv[0]);
+ types = apr_palloc(cmd->pool, argc * sizeof(char *));
+ memcpy(types, &argv[1], (argc - 1) * sizeof(char *));
+ types[argc] = NULL;
+ for (pname = apr_strtok(name, ";", &strtok_state);
+ pname != NULL && rv == NULL;
+ pname = apr_strtok(NULL, ";", &strtok_state)) {
+ rv = filter_bytype1(cmd, CFG, pname, types);
+ }
+ return rv;
+}
+
static const char *filter_debug(cmd_parms *cmd, void *CFG, const char *fname,
const char *level)
{
@@ -761,14 +633,14 @@ static void filter_insert(request_rec *r)
* through the chain, and prune out the NULL filters */
for (p = cfg->chain; p; p = p->next) {
- if (p->fname == NULL)
+ if (p->fname == NULL)
cfg->chain = p->next;
}
for (p = cfg->chain; p; p = p->next) {
filter = apr_hash_get(cfg->live_filters, p->fname, APR_HASH_KEY_STRING);
if (filter == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01380)
"Unknown filter %s not added", p->fname);
continue;
}
@@ -853,14 +725,15 @@ static void *filter_merge(apr_pool_t *pool, void *BASE, void *ADD)
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"),
+ "filter-name [filter-type]"),
+ AP_INIT_TAKE3("FilterProvider", filter_provider, NULL, OR_OPTIONS,
+ "filter-name provider-name match-expression"),
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"),
+ "filter-name debug-level"),
+ AP_INIT_TAKE_ARGV("AddOutputFilterByType", filter_bytype, NULL, OR_FILEINFO,
+ "output filter name followed by one or more content-types"),
#ifndef NO_PROTOCOL
AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_OPTIONS,
"filter-name [provider-name] protocol-args"),
@@ -868,7 +741,7 @@ static const command_rec filter_cmds[] = {
{ NULL }
};
-module AP_MODULE_DECLARE_DATA filter_module = {
+AP_DECLARE_MODULE(filter) = {
STANDARD20_MODULE_STUFF,
filter_config,
filter_merge,
diff --git a/modules/filters/mod_filter.dep b/modules/filters/mod_filter.dep
deleted file mode 100644
index dda01b4e..00000000
--- a/modules/filters/mod_filter.dep
+++ /dev/null
@@ -1,27 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_filter.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_filter.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.h"\
- "..\..\include\http_config.h"\
- "..\..\include\http_log.h"\
- "..\..\include\http_request.h"\
- "..\..\include\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_filter.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_hash.h"\
- "..\..\srclib\apr\include\apr_lib.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
-
diff --git a/modules/filters/mod_filter.mak b/modules/filters/mod_filter.mak
deleted file mode 100644
index c1728072..00000000
--- a/modules/filters/mod_filter.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_filter.dsp
-!IF "$(CFG)" == ""
-CFG=mod_filter - Win32 Release
-!MESSAGE No configuration specified. Defaulting to mod_filter - Win32 Release.
-!ENDIF
-
-!IF "$(CFG)" != "mod_filter - Win32 Release" && "$(CFG)" != "mod_filter - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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_filter.mak" CFG="mod_filter - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_filter - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_filter - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_filter - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_filter.obj"
- -@erase "$(INTDIR)\mod_filter.res"
- -@erase "$(INTDIR)\mod_filter_src.idb"
- -@erase "$(INTDIR)\mod_filter_src.pdb"
- -@erase "$(OUTDIR)\mod_filter.exp"
- -@erase "$(OUTDIR)\mod_filter.lib"
- -@erase "$(OUTDIR)\mod_filter.pdb"
- -@erase "$(OUTDIR)\mod_filter.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_filter_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_filter.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_filter.so" /d LONG_NAME="filter_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_filter.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_filter.pdb" /debug /out:"$(OUTDIR)\mod_filter.so" /implib:"$(OUTDIR)\mod_filter.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_filter.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_filter.obj" \
- "$(INTDIR)\mod_filter.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_filter.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_filter.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_filter.so"
- if exist .\Release\mod_filter.so.manifest mt.exe -manifest .\Release\mod_filter.so.manifest -outputresource:.\Release\mod_filter.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_filter - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_filter.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_filter.obj"
- -@erase "$(INTDIR)\mod_filter.res"
- -@erase "$(INTDIR)\mod_filter_src.idb"
- -@erase "$(INTDIR)\mod_filter_src.pdb"
- -@erase "$(OUTDIR)\mod_filter.exp"
- -@erase "$(OUTDIR)\mod_filter.lib"
- -@erase "$(OUTDIR)\mod_filter.pdb"
- -@erase "$(OUTDIR)\mod_filter.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_filter_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_filter.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_filter.so" /d LONG_NAME="filter_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_filter.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_filter.pdb" /debug /out:"$(OUTDIR)\mod_filter.so" /implib:"$(OUTDIR)\mod_filter.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_filter.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_filter.obj" \
- "$(INTDIR)\mod_filter.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_filter.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_filter.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_filter.so"
- if exist .\Debug\mod_filter.so.manifest mt.exe -manifest .\Debug\mod_filter.so.manifest -outputresource:.\Debug\mod_filter.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_filter.dep")
-!INCLUDE "mod_filter.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_filter.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_filter - Win32 Release" || "$(CFG)" == "mod_filter - Win32 Debug"
-
-!IF "$(CFG)" == "mod_filter - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_filter - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_filter - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_filter - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_filter - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_filter - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_filter - Win32 Release"
-
-
-"$(INTDIR)\mod_filter.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_filter.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_filter.so" /d LONG_NAME="filter_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_filter - Win32 Debug"
-
-
-"$(INTDIR)\mod_filter.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_filter.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_filter.so" /d LONG_NAME="filter_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_filter.c
-
-"$(INTDIR)\mod_filter.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c
index 59ce8e3e..ffca2328 100644
--- a/modules/filters/mod_include.c
+++ b/modules/filters/mod_include.c
@@ -39,6 +39,7 @@
#include "util_script.h"
#include "http_core.h"
#include "mod_include.h"
+#include "ap_expr.h"
/* helper for Latin1 <-> entity encoding */
#if APR_CHARSET_EBCDIC
@@ -107,7 +108,8 @@ typedef struct parse_node {
typedef enum {
XBITHACK_OFF,
XBITHACK_ON,
- XBITHACK_FULL
+ XBITHACK_FULL,
+ XBITHACK_UNSET
} xbithack_t;
typedef struct {
@@ -115,9 +117,9 @@ typedef struct {
const char *default_time_fmt;
const char *undefined_echo;
xbithack_t xbithack;
- int accessenable;
- int lastmodified;
- int etag;
+ signed char lastmodified;
+ signed char etag;
+ signed char legacy_expr;
} include_dir_config;
typedef struct {
@@ -160,7 +162,7 @@ typedef struct {
const char *rexp;
apr_size_t nsub;
ap_regmatch_t match[AP_MAX_REG_MATCH];
- int have_match;
+ int have_match;
} backref_t;
typedef struct {
@@ -179,7 +181,6 @@ struct ssi_internal_ctx {
apr_bucket_brigade *tmp_bb;
- request_rec *r;
const char *start_seq;
bndm_t *start_seq_pat;
const char *end_seq;
@@ -195,8 +196,12 @@ struct ssi_internal_ctx {
const char *undefined_echo;
apr_size_t undefined_echo_len;
- int accessenable; /* is using the access tests allowed? */
+ char legacy_expr; /* use ap_expr or legacy mod_include
+ expression parser? */
+ ap_expr_eval_ctx_t *expr_eval_ctx; /* NULL if there wasn't an ap_expr yet */
+ const char *expr_vary_this; /* for use by ap_expr_eval_ctx */
+ const char *expr_err; /* for use by ap_expr_eval_ctx */
#ifdef DEBUG_INCLUDE
struct {
ap_filter_t *f;
@@ -454,7 +459,7 @@ static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
/* Sentinel value to store in subprocess_env for items that
* shouldn't be evaluated until/unless they're actually used
*/
-static const char lazy_eval_sentinel;
+static const char lazy_eval_sentinel = '\0';
#define LAZY_VALUE (&lazy_eval_sentinel)
/* default values */
@@ -463,9 +468,8 @@ static const char lazy_eval_sentinel;
#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
#define DEFAULT_UNDEFINED_ECHO "(none)"
-#define DEFAULT_ACCESSENABLE 0
-#define DEFAULT_LASTMODIFIED 0
-#define DEFAULT_ETAG 0
+
+#define UNSET -1
#ifdef XBITHACK
#define DEFAULT_XBITHACK XBITHACK_FULL
@@ -644,7 +648,7 @@ static const char *add_include_vars_lazy(request_rec *r, const char *var, const
static const char *get_include_var(const char *var, include_ctx_t *ctx)
{
const char *val;
- request_rec *r = ctx->intern->r;
+ request_rec *r = ctx->r;
if (apr_isdigit(*var) && !var[1]) {
apr_size_t idx = *var - '0';
@@ -655,22 +659,20 @@ static const char *get_include_var(const char *var, include_ctx_t *ctx)
* v.s. empty strings on an empty match is deliberate.
*/
if (!re || !re->have_match) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01329)
"regex capture $%" APR_SIZE_T_FMT " refers to no regex in %s",
idx, r->filename);
return NULL;
}
else if (re->nsub < idx || idx >= AP_MAX_REG_MATCH) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01330)
"regex capture $%" APR_SIZE_T_FMT
" is out of range (last regex was: '%s') in %s",
idx, re->rexp, r->filename);
return NULL;
}
else if (re->match[idx].rm_so < 0 || re->match[idx].rm_eo < 0) {
- /* I don't think this can happen if have_match is true.
- * But let's not risk a regression by dropping this
- */
+ /* This particular subpattern was not used by the regex */
return NULL;
}
else {
@@ -689,6 +691,48 @@ static const char *get_include_var(const char *var, include_ctx_t *ctx)
return val;
}
+static const char *include_expr_var_fn(ap_expr_eval_ctx_t *eval_ctx,
+ const void *data,
+ const char *arg)
+{
+ const char *res, *name = data;
+ include_ctx_t *ctx = eval_ctx->data;
+ if (name[0] == 'e') {
+ /* keep legacy "env" semantics */
+ if ((res = apr_table_get(ctx->r->notes, arg)) != NULL)
+ return res;
+ else if ((res = get_include_var(arg, ctx)) != NULL)
+ return res;
+ else
+ return getenv(arg);
+ }
+ else {
+ return get_include_var(arg, ctx);
+ }
+}
+
+static int include_expr_lookup(ap_expr_lookup_parms *parms)
+{
+ switch (parms->type) {
+ case AP_EXPR_FUNC_STRING:
+ if (strcasecmp(parms->name, "v") == 0 ||
+ strcasecmp(parms->name, "reqenv") == 0 ||
+ strcasecmp(parms->name, "env") == 0) {
+ *parms->func = include_expr_var_fn;
+ *parms->data = parms->name;
+ return OK;
+ }
+ break;
+ /*
+ * We could also make the SSI vars available as %{...} style variables
+ * (AP_EXPR_FUNC_VAR), but this would create problems if we ever want
+ * to cache parsed expressions for performance reasons.
+ */
+ }
+ return ap_run_expr_lookup(parms);
+}
+
+
/*
* Do variable substitution on strings
*
@@ -698,7 +742,7 @@ static const char *get_include_var(const char *var, include_ctx_t *ctx)
static char *ap_ssi_parse_string(include_ctx_t *ctx, const char *in, char *out,
apr_size_t length, int leave_name)
{
- request_rec *r = ctx->intern->r;
+ request_rec *r = ctx->r;
result_item_t *result = NULL, *current = NULL;
apr_size_t outlen = 0, inlen, span;
char *ret = NULL, *eout = NULL;
@@ -784,7 +828,7 @@ static char *ap_ssi_parse_string(include_ctx_t *ctx, const char *in, char *out,
if (*++p == '{') {
ep = ap_strchr_c(++p, '}');
if (!ep) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Missing '}' on "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01331) "Missing '}' on "
"variable \"%s\" in %s", p, r->filename);
break;
}
@@ -924,7 +968,7 @@ static APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
compiled = ap_pregcomp(ctx->dpool, rexp, AP_REG_EXTENDED);
if (!compiled) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->intern->r, "unable to "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "unable to "
"compile pattern \"%s\"", rexp);
return -1;
}
@@ -936,7 +980,7 @@ static APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
re->source = apr_pstrdup(ctx->pool, string);
re->rexp = apr_pstrdup(ctx->pool, rexp);
re->nsub = compiled->re_nsub;
- re->have_match = !ap_regexec(compiled, string, AP_MAX_REG_MATCH,
+ re->have_match = !ap_regexec(compiled, string, AP_MAX_REG_MATCH,
re->match, 0);
ap_pregfree(ctx->dpool, compiled);
@@ -1030,7 +1074,7 @@ static int get_ptoken(include_ctx_t *ctx, const char **parse, token_t *token, to
TYPE_TOKEN(token, TOKEN_LT);
return 0;
case '-':
- if (**parse == 'A' && (ctx->intern->accessenable)) {
+ if (**parse == 'A') {
TYPE_TOKEN(token, TOKEN_ACCESS);
++*parse;
return 0;
@@ -1123,11 +1167,10 @@ static int get_ptoken(include_ctx_t *ctx, const char **parse, token_t *token, to
static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
{
parse_node_t *new, *root = NULL, *current = NULL;
- request_rec *r = ctx->intern->r;
+ request_rec *r = ctx->r;
request_rec *rr = NULL;
const char *error = "Invalid expression \"%s\" in file %s";
const char *parse = expr;
- int was_unmatched = 0;
unsigned regex = 0;
*was_error = 0;
@@ -1144,14 +1187,18 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
*/
CREATE_NODE(ctx, new);
- was_unmatched = get_ptoken(ctx, &parse, &new->token,
- (current != NULL ? &current->token : NULL));
- if (!parse) {
- break;
- }
+ {
+#ifdef DEBUG_INCLUDE
+ int was_unmatched =
+#endif
+ get_ptoken(ctx, &parse, &new->token,
+ (current != NULL ? &current->token : NULL));
+ if (!parse)
+ break;
- DEBUG_DUMP_UNMATCHED(ctx, was_unmatched);
- DEBUG_DUMP_TOKEN(ctx, &new->token);
+ DEBUG_DUMP_UNMATCHED(ctx, was_unmatched);
+ DEBUG_DUMP_TOKEN(ctx, &new->token);
+ }
if (!current) {
switch (new->token.type) {
@@ -1335,7 +1382,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
case TOKEN_AND:
case TOKEN_OR:
if (!current->left || !current->right) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01332)
"Invalid expression \"%s\" in file %s",
expr, r->filename);
*was_error = 1;
@@ -1400,7 +1447,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
current->left->token.type != TOKEN_STRING ||
(current->right->token.type != TOKEN_STRING &&
current->right->token.type != TOKEN_RE)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01333)
"Invalid expression \"%s\" in file %s",
expr, r->filename);
*was_error = 1;
@@ -1435,7 +1482,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
if (!current->left || !current->right ||
current->left->token.type != TOKEN_STRING ||
current->right->token.type != TOKEN_STRING) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01334)
"Invalid expression \"%s\" in file %s",
expr, r->filename);
*was_error = 1;
@@ -1483,7 +1530,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
if (current->left || !current->right ||
(current->right->token.type != TOKEN_STRING &&
current->right->token.type != TOKEN_RE)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01335)
"Invalid expression \"%s\" in file %s: Token '-A' must be followed by a URI string.",
expr, r->filename);
*was_error = 1;
@@ -1499,7 +1546,7 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
}
else {
current->value = 0;
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rr->status, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rr->status, r, APLOGNO(01336)
"mod_include: The tested "
"subrequest -A \"%s\" returned an error code.",
current->right->token.value);
@@ -1533,6 +1580,69 @@ static int parse_expr(include_ctx_t *ctx, const char *expr, int *was_error)
return (root ? root->value : 0);
}
+/* same as above, but use common ap_expr syntax / API */
+static int parse_ap_expr(include_ctx_t *ctx, const char *expr, int *was_error)
+{
+ ap_expr_info_t expr_info;
+ const char *err;
+ int ret;
+ backref_t *re = ctx->intern->re;
+ ap_expr_eval_ctx_t *eval_ctx = ctx->intern->expr_eval_ctx;
+
+ expr_info.filename = ctx->r->filename;
+ expr_info.line_number = 0;
+ expr_info.module_index = APLOG_MODULE_INDEX;
+ expr_info.flags = AP_EXPR_FLAG_RESTRICTED;
+ err = ap_expr_parse(ctx->r->pool, ctx->r->pool, &expr_info, expr,
+ include_expr_lookup);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(01337)
+ "Could not parse expr \"%s\" in %s: %s", expr,
+ ctx->r->filename, err);
+ *was_error = 1;
+ return 0;
+ }
+
+ if (!re) {
+ ctx->intern->re = re = apr_pcalloc(ctx->pool, sizeof(*re));
+ }
+ else {
+ /* ap_expr_exec_ctx() does not care about re->have_match but only about
+ * re->source
+ */
+ if (!re->have_match)
+ re->source = NULL;
+ }
+
+ if (!eval_ctx) {
+ eval_ctx = apr_pcalloc(ctx->pool, sizeof(*eval_ctx));
+ ctx->intern->expr_eval_ctx = eval_ctx;
+ eval_ctx->r = ctx->r;
+ eval_ctx->c = ctx->r->connection;
+ eval_ctx->s = ctx->r->server;
+ eval_ctx->p = ctx->r->pool;
+ eval_ctx->data = ctx;
+ eval_ctx->err = &ctx->intern->expr_err;
+ eval_ctx->vary_this = &ctx->intern->expr_vary_this;
+ eval_ctx->re_nmatch = AP_MAX_REG_MATCH;
+ eval_ctx->re_pmatch = re->match;
+ eval_ctx->re_source = &re->source;
+ }
+
+ eval_ctx->info = &expr_info;
+ ret = ap_expr_exec_ctx(eval_ctx);
+ if (ret < 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(01338)
+ "Could not evaluate expr \"%s\" in %s: %s", expr,
+ ctx->r->filename, ctx->intern->expr_err);
+ *was_error = 1;
+ return 0;
+ }
+ *was_error = 0;
+ if (re->source)
+ re->have_match = 1;
+ return ret;
+}
/*
* +-------------------------------------------------------+
@@ -1596,7 +1706,7 @@ static int find_file(request_rec *r, const char *directive, const char *tag,
we never attempt to "run" this sub request. */
rr = ap_sub_req_lookup_file(newpath, r, NULL);
- if (rr->status == HTTP_OK && rr->finfo.filetype != 0) {
+ if (rr->status == HTTP_OK && rr->finfo.filetype != APR_NOFILE) {
to_send = rr->filename;
if ((rv = apr_stat(finfo, to_send,
APR_FINFO_GPROT | APR_FINFO_MIN, rr->pool)) != APR_SUCCESS
@@ -1626,14 +1736,14 @@ static int find_file(request_rec *r, const char *directive, const char *tag,
we never attempt to "run" this sub request. */
rr = ap_sub_req_lookup_uri(tag_val, r, NULL);
- if (rr->status == HTTP_OK && rr->finfo.filetype != 0) {
+ if (rr->status == HTTP_OK && rr->finfo.filetype != APR_NOFILE) {
memcpy((char *) finfo, (const char *) &rr->finfo,
sizeof(rr->finfo));
ap_destroy_sub_req(rr);
return 0;
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unable to get "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01339) "unable to get "
"information about \"%s\" in parsed file %s",
tag_val, r->filename);
ap_destroy_sub_req(rr);
@@ -1641,25 +1751,33 @@ static int find_file(request_rec *r, const char *directive, const char *tag,
}
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01340) "unknown parameter \"%s\" "
"to tag %s in %s", tag, directive, r->filename);
return -1;
}
}
/*
- * <!--#include virtual|file="..." [virtual|file="..."] ... -->
+ * <!--#include virtual|file="..." [onerror|virtual|file="..."] ... -->
+ *
+ * Output each file/virtual in turn until one of them returns an error.
+ * On error, ignore all further file/virtual attributes until we reach
+ * an onerror attribute, where we make an attempt to serve the onerror
+ * virtual url. If onerror fails, or no onerror is present, the default
+ * error string is inserted into the stream.
*/
static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
apr_bucket_brigade *bb)
{
request_rec *r = f->r;
+ char *last_error;
if (!ctx->argc) {
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "missing argument for include element in %s",
+ 0, r, APLOGNO(01341)
+ "missing argument for include element in %s",
r->filename);
}
@@ -1672,6 +1790,7 @@ static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
return APR_SUCCESS;
}
+ last_error = NULL;
while (1) {
char *tag = NULL;
char *tag_val = NULL;
@@ -1684,8 +1803,9 @@ static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
break;
}
- if (strcmp(tag, "virtual") && strcmp(tag, "file")) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
+ if (strcmp(tag, "virtual") && strcmp(tag, "file") && strcmp(tag,
+ "onerror")) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01342) "unknown parameter "
"\"%s\" to tag include in %s", tag, r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
break;
@@ -1709,8 +1829,17 @@ static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
rr = ap_sub_req_lookup_file(newpath, r, f->next);
}
}
+ else if ((tag[0] == 'v' && !last_error)
+ || (tag[0] == 'o' && last_error)) {
+ if (r->kept_body) {
+ rr = ap_sub_req_method_uri(r->method, parsed_string, r, f->next);
+ }
+ else {
+ rr = ap_sub_req_lookup_uri(parsed_string, r, f->next);
+ }
+ }
else {
- rr = ap_sub_req_lookup_uri(parsed_string, r, f->next);
+ continue;
}
if (!error_fmt && rr->status != HTTP_OK) {
@@ -1738,8 +1867,15 @@ static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
if (error_fmt) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, error_fmt, tag_val,
- r->filename);
- SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ r->filename);
+ if (last_error) {
+ /* onerror threw an error, give up completely */
+ break;
+ }
+ last_error = error_fmt;
+ }
+ else {
+ last_error = NULL;
}
/* Do *not* destroy the subrequest here; it may have allocated
@@ -1747,28 +1883,32 @@ static apr_status_t handle_include(include_ctx_t *ctx, ap_filter_t *f,
* r->pool, so that pool must survive as long as this request.
* Yes, this is a memory leak. */
- if (error_fmt) {
- break;
- }
+ }
+
+ if (last_error) {
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
}
return APR_SUCCESS;
}
/*
- * <!--#echo [encoding="..."] var="..." [encoding="..."] var="..." ... -->
+ * <!--#echo [decoding="..."] [encoding="..."] var="..." [decoding="..."]
+ * [encoding="..."] var="..." ... -->
*/
static apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
apr_bucket_brigade *bb)
{
- enum {E_NONE, E_URL, E_ENTITY} encode;
+ const char *encoding = "entity", *decoding = "none";
request_rec *r = f->r;
+ int error = 0;
if (!ctx->argc) {
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "missing argument for echo element in %s",
+ 0, r, APLOGNO(01343)
+ "missing argument for echo element in %s",
r->filename);
}
@@ -1781,8 +1921,6 @@ static apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
return APR_SUCCESS;
}
- encode = E_ENTITY;
-
while (1) {
char *tag = NULL;
char *tag_val = NULL;
@@ -1802,17 +1940,77 @@ static apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
ctx);
if (val) {
- switch(encode) {
- case E_NONE:
- echo_text = val;
- break;
- case E_URL:
- echo_text = ap_escape_uri(ctx->dpool, val);
- break;
- case E_ENTITY:
- /* PR#25202: escape anything non-ascii here */
- echo_text = ap_escape_html2(ctx->dpool, val, 1);
- break;
+ char *last = NULL;
+ char *e, *d, *token;
+
+ echo_text = val;
+
+ d = apr_pstrdup(ctx->pool, decoding);
+ token = apr_strtok(d, ", \t", &last);
+
+ while(token) {
+ if (!strcasecmp(token, "none")) {
+ /* do nothing */
+ }
+ else if (!strcasecmp(token, "url")) {
+ char *buf = apr_pstrdup(ctx->pool, echo_text);
+ ap_unescape_url(buf);
+ echo_text = buf;
+ }
+ else if (!strcasecmp(token, "urlencoded")) {
+ char *buf = apr_pstrdup(ctx->pool, echo_text);
+ ap_unescape_urlencoded(buf);
+ echo_text = buf;
+ }
+ else if (!strcasecmp(token, "entity")) {
+ char *buf = apr_pstrdup(ctx->pool, echo_text);
+ decodehtml(buf);
+ echo_text = buf;
+ }
+ else if (!strcasecmp(token, "base64")) {
+ echo_text = ap_pbase64decode(ctx->dpool, echo_text);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01344) "unknown value "
+ "\"%s\" to parameter \"decoding\" of tag echo in "
+ "%s", token, r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ error = 1;
+ break;
+ }
+ token = apr_strtok(NULL, ", \t", &last);
+ }
+
+ e = apr_pstrdup(ctx->pool, encoding);
+ token = apr_strtok(e, ", \t", &last);
+
+ while(token) {
+ if (!strcasecmp(token, "none")) {
+ /* do nothing */
+ }
+ else if (!strcasecmp(token, "url")) {
+ echo_text = ap_escape_uri(ctx->dpool, echo_text);
+ }
+ else if (!strcasecmp(token, "urlencoded")) {
+ echo_text = ap_escape_urlencoded(ctx->dpool, echo_text);
+ }
+ else if (!strcasecmp(token, "entity")) {
+ echo_text = ap_escape_html2(ctx->dpool, echo_text, 0);
+ }
+ else if (!strcasecmp(token, "base64")) {
+ char *buf;
+ buf = ap_pbase64encode(ctx->dpool, (char *)echo_text);
+ echo_text = buf;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01345) "unknown value "
+ "\"%s\" to parameter \"encoding\" of tag echo in "
+ "%s", token, r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ error = 1;
+ break;
+ }
+ token = apr_strtok(NULL, ", \t", &last);
}
e_len = strlen(echo_text);
@@ -1822,30 +2020,22 @@ static apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
e_len = ctx->intern->undefined_echo_len;
}
+ if (error) {
+ break;
+ }
+
APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(
apr_pmemdup(ctx->pool, echo_text, e_len),
e_len, ctx->pool, f->c->bucket_alloc));
}
+ else if (!strcmp(tag, "decoding")) {
+ decoding = tag_val;
+ }
else if (!strcmp(tag, "encoding")) {
- if (!strcasecmp(tag_val, "none")) {
- encode = E_NONE;
- }
- else if (!strcasecmp(tag_val, "url")) {
- encode = E_URL;
- }
- else if (!strcasecmp(tag_val, "entity")) {
- encode = E_ENTITY;
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown value "
- "\"%s\" to parameter \"encoding\" of tag echo in "
- "%s", tag_val, r->filename);
- SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
- break;
- }
+ encoding = tag_val;
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01346) "unknown parameter "
"\"%s\" in tag echo of %s", tag, r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
break;
@@ -1869,7 +2059,8 @@ static apr_status_t handle_config(include_ctx_t *ctx, ap_filter_t *f,
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "missing argument for config element in %s",
+ 0, r, APLOGNO(01347)
+ "missing argument for config element in %s",
r->filename);
}
@@ -1926,7 +2117,7 @@ static apr_status_t handle_config(include_ctx_t *ctx, ap_filter_t *f,
ctx->flags &= SSI_FLAG_SIZE_ABBREV;
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown value "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01348) "unknown value "
"\"%s\" to parameter \"sizefmt\" of tag config "
"in %s", parsed_string, r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
@@ -1934,7 +2125,7 @@ static apr_status_t handle_config(include_ctx_t *ctx, ap_filter_t *f,
}
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01349) "unknown parameter "
"\"%s\" to tag config in %s", tag, r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
break;
@@ -1956,7 +2147,8 @@ static apr_status_t handle_fsize(include_ctx_t *ctx, ap_filter_t *f,
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "missing argument for fsize element in %s",
+ 0, r, APLOGNO(01350)
+ "missing argument for fsize element in %s",
r->filename);
}
@@ -2043,7 +2235,8 @@ static apr_status_t handle_flastmod(include_ctx_t *ctx, ap_filter_t *f,
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "missing argument for flastmod element in %s",
+ 0, r, APLOGNO(01351)
+ "missing argument for flastmod element in %s",
r->filename);
}
@@ -2104,9 +2297,10 @@ static apr_status_t handle_if(include_ctx_t *ctx, ap_filter_t *f,
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, (ctx->argc)
- ? "too many arguments for if element in %s"
- : "missing expr argument for if element in %s",
+ 0, r,
+ (ctx->argc)
+ ? APLOGNO(01352) "too many arguments for if element in %s"
+ : APLOGNO(01353) "missing expr argument for if element in %s",
r->filename);
}
@@ -2123,14 +2317,14 @@ static apr_status_t handle_if(include_ctx_t *ctx, ap_filter_t *f,
ap_ssi_get_tag_and_value(ctx, &tag, &expr, SSI_VALUE_RAW);
if (strcmp(tag, "expr")) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01354) "unknown parameter \"%s\" "
"to tag if in %s", tag, r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
if (!expr) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "missing expr value for if "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01355) "missing expr value for if "
"element in %s", r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
@@ -2138,7 +2332,10 @@ static apr_status_t handle_if(include_ctx_t *ctx, ap_filter_t *f,
DEBUG_PRINTF((ctx, "**** if expr=\"%s\"\n", expr));
- expr_ret = parse_expr(ctx, expr, &was_error);
+ if (ctx->intern->legacy_expr)
+ expr_ret = parse_expr(ctx, expr, &was_error);
+ else
+ expr_ret = parse_ap_expr(ctx, expr, &was_error);
if (was_error) {
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
@@ -2173,9 +2370,10 @@ static apr_status_t handle_elif(include_ctx_t *ctx, ap_filter_t *f,
if (ctx->argc != 1) {
ap_log_rerror(APLOG_MARK,
(!(ctx->if_nesting_level)) ? APLOG_ERR : APLOG_WARNING,
- 0, r, (ctx->argc)
- ? "too many arguments for if element in %s"
- : "missing expr argument for if element in %s",
+ 0, r,
+ (ctx->argc)
+ ? APLOGNO(01356) "too many arguments for if element in %s"
+ : APLOGNO(01357) "missing expr argument for if element in %s",
r->filename);
}
@@ -2191,14 +2389,14 @@ static apr_status_t handle_elif(include_ctx_t *ctx, ap_filter_t *f,
ap_ssi_get_tag_and_value(ctx, &tag, &expr, SSI_VALUE_RAW);
if (strcmp(tag, "expr")) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter \"%s\" "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01358) "unknown parameter \"%s\" "
"to tag if in %s", tag, r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
}
if (!expr) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "missing expr in elif "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01359) "missing expr in elif "
"statement: %s", r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
return APR_SUCCESS;
@@ -2242,7 +2440,8 @@ static apr_status_t handle_else(include_ctx_t *ctx, ap_filter_t *f,
if (ctx->argc) {
ap_log_rerror(APLOG_MARK,
(!(ctx->if_nesting_level)) ? APLOG_ERR : APLOG_WARNING,
- 0, r, "else directive does not take tags in %s",
+ 0, r, APLOGNO(01360)
+ "else directive does not take tags in %s",
r->filename);
}
@@ -2281,7 +2480,8 @@ static apr_status_t handle_endif(include_ctx_t *ctx, ap_filter_t *f,
if (ctx->argc) {
ap_log_rerror(APLOG_MARK,
(!(ctx->if_nesting_level)) ? APLOG_ERR : APLOG_WARNING,
- 0, r, "endif directive does not take tags in %s",
+ 0, r, APLOGNO(01361)
+ "endif directive does not take tags in %s",
r->filename);
}
@@ -2308,16 +2508,19 @@ static apr_status_t handle_endif(include_ctx_t *ctx, ap_filter_t *f,
static apr_status_t handle_set(include_ctx_t *ctx, ap_filter_t *f,
apr_bucket_brigade *bb)
{
+ const char *encoding = "none", *decoding = "none";
char *var = NULL;
request_rec *r = f->r;
request_rec *sub = r->main;
apr_pool_t *p = r->pool;
+ int error = 0;
if (ctx->argc < 2) {
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "missing argument for set element in %s",
+ 0, r,
+ APLOGNO(01362) "missing argument for set element in %s",
r->filename);
}
@@ -2342,21 +2545,28 @@ static apr_status_t handle_set(include_ctx_t *ctx, ap_filter_t *f,
char *tag = NULL;
char *tag_val = NULL;
- ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
+ ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, SSI_VALUE_RAW);
if (!tag || !tag_val) {
break;
}
if (!strcmp(tag, "var")) {
+ decodehtml(tag_val);
var = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
}
+ else if (!strcmp(tag, "decoding")) {
+ decoding = tag_val;
+ }
+ else if (!strcmp(tag, "encoding")) {
+ encoding = tag_val;
+ }
else if (!strcmp(tag, "value")) {
char *parsed_string;
if (!var) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "variable must "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01363) "variable must "
"precede value in set directive in %s",
r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
@@ -2365,11 +2575,90 @@ static apr_status_t handle_set(include_ctx_t *ctx, ap_filter_t *f,
parsed_string = ap_ssi_parse_string(ctx, tag_val, NULL, 0,
SSI_EXPAND_DROP_NAME);
+
+ if (parsed_string) {
+ char *last = NULL;
+ char *e, *d, *token;
+
+ d = apr_pstrdup(ctx->pool, decoding);
+ token = apr_strtok(d, ", \t", &last);
+
+ while(token) {
+ if (!strcasecmp(token, "none")) {
+ /* do nothing */
+ }
+ else if (!strcasecmp(token, "url")) {
+ char *buf = apr_pstrdup(ctx->pool, parsed_string);
+ ap_unescape_url(buf);
+ parsed_string = buf;
+ }
+ else if (!strcasecmp(token, "urlencoded")) {
+ char *buf = apr_pstrdup(ctx->pool, parsed_string);
+ ap_unescape_urlencoded(buf);
+ parsed_string = buf;
+ }
+ else if (!strcasecmp(token, "entity")) {
+ char *buf = apr_pstrdup(ctx->pool, parsed_string);
+ decodehtml(buf);
+ parsed_string = buf;
+ }
+ else if (!strcasecmp(token, "base64")) {
+ parsed_string = ap_pbase64decode(ctx->dpool, parsed_string);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01364) "unknown value "
+ "\"%s\" to parameter \"decoding\" of tag set in "
+ "%s", token, r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ error = 1;
+ break;
+ }
+ token = apr_strtok(NULL, ", \t", &last);
+ }
+
+ e = apr_pstrdup(ctx->pool, encoding);
+ token = apr_strtok(e, ", \t", &last);
+
+ while(token) {
+ if (!strcasecmp(token, "none")) {
+ /* do nothing */
+ }
+ else if (!strcasecmp(token, "url")) {
+ parsed_string = ap_escape_uri(ctx->dpool, parsed_string);
+ }
+ else if (!strcasecmp(token, "urlencoded")) {
+ parsed_string = ap_escape_urlencoded(ctx->dpool, parsed_string);
+ }
+ else if (!strcasecmp(token, "entity")) {
+ parsed_string = ap_escape_html2(ctx->dpool, parsed_string, 0);
+ }
+ else if (!strcasecmp(token, "base64")) {
+ char *buf;
+ buf = ap_pbase64encode(ctx->dpool, (char *)parsed_string);
+ parsed_string = buf;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01365) "unknown value "
+ "\"%s\" to parameter \"encoding\" of tag set in "
+ "%s", token, r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ error = 1;
+ break;
+ }
+ token = apr_strtok(NULL, ", \t", &last);
+ }
+
+ }
+
+ if (error) {
+ break;
+ }
+
apr_table_setn(r->subprocess_env, apr_pstrdup(p, var),
apr_pstrdup(p, parsed_string));
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Invalid tag for set "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01366) "Invalid tag for set "
"directive in %s", r->filename);
SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
break;
@@ -2394,7 +2683,8 @@ static apr_status_t handle_printenv(include_ctx_t *ctx, ap_filter_t *f,
ap_log_rerror(APLOG_MARK,
(ctx->flags & SSI_FLAG_PRINTING)
? APLOG_ERR : APLOG_WARNING,
- 0, r, "printenv directive does not take tags in %s",
+ 0, r,
+ APLOGNO(01367) "printenv directive does not take tags in %s",
r->filename);
}
@@ -2412,36 +2702,18 @@ static apr_status_t handle_printenv(include_ctx_t *ctx, ap_filter_t *f,
for (i = 0; i < arr->nelts; ++i) {
const char *key_text, *val_text;
- char *key_val, *next;
- apr_size_t k_len, v_len, kv_length;
/* get key */
key_text = ap_escape_html(ctx->dpool, elts[i].key);
- k_len = strlen(key_text);
/* get value */
val_text = elts[i].val;
- if (val_text == LAZY_VALUE) {
+ if (val_text == LAZY_VALUE)
val_text = add_include_vars_lazy(r, elts[i].key, ctx->time_str);
- }
- val_text = ap_escape_html(ctx->dpool, elts[i].val);
- v_len = strlen(val_text);
+ val_text = ap_escape_html(ctx->dpool, val_text);
- /* assemble result */
- kv_length = k_len + v_len + sizeof("=\n");
- key_val = apr_palloc(ctx->pool, kv_length);
- next = key_val;
-
- memcpy(next, key_text, k_len);
- next += k_len;
- *next++ = '=';
- memcpy(next, val_text, v_len);
- next += v_len;
- *next++ = '\n';
- *next = 0;
-
- APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(key_val, kv_length-1,
- ctx->pool, f->c->bucket_alloc));
+ apr_brigade_putstrs(bb, NULL, NULL, key_text, "=", val_text, "\n",
+ NULL);
}
ctx->flush_now = 1;
@@ -2784,9 +3056,9 @@ static apr_size_t find_directive(include_ctx_t *ctx, const char *data,
if (!intern->directive_len) {
intern->error = 1;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(01368) "missing "
"directive name in parsed document %s",
- intern->r->filename);
+ ctx->r->filename);
}
else {
char *sp = intern->directive;
@@ -2920,11 +3192,11 @@ static apr_size_t find_argument(include_ctx_t *ctx, const char *data,
intern->current_arg->name_len = 0;
intern->error = 1;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(01369) "missing "
"argument name for value to tag %s in %s",
- apr_pstrmemdup(intern->r->pool, intern->directive,
+ apr_pstrmemdup(ctx->r->pool, intern->directive,
intern->directive_len),
- intern->r->filename);
+ ctx->r->filename);
return (p - data);
@@ -2952,20 +3224,14 @@ static apr_size_t find_argument(include_ctx_t *ctx, const char *data,
intern->current_arg->name_len);
if (!intern->current_arg->name_len) {
intern->error = 1;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, intern->r, "missing "
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(01370) "missing "
"argument name for value to tag %s in %s",
- apr_pstrmemdup(intern->r->pool, intern->directive,
+ apr_pstrmemdup(ctx->r->pool, intern->directive,
intern->directive_len),
- intern->r->filename);
+ ctx->r->filename);
}
else {
- char *sp = intern->current_arg->name;
-
- /* normalize the name */
- while (*sp) {
- *sp = apr_tolower(*sp);
- ++sp;
- }
+ ap_str_tolower(intern->current_arg->name);
}
intern->state = PARSE_ARG_EQ;
@@ -3126,7 +3392,6 @@ static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
/* initialization for this loop */
intern->bytes_read = 0;
intern->error = 0;
- intern->r = r;
ctx->flush_now = 0;
/* loop over the current bucket brigade */
@@ -3435,7 +3700,7 @@ static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
}
}
else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01371)
"unknown directive \"%s\" in parsed doc %s",
apr_pstrmemdup(r->pool, intern->directive,
intern->directive_len),
@@ -3472,7 +3737,7 @@ static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
}
}
else if (PARSE_PRE_HEAD != intern->state) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01372)
"SSI directive was not properly finished at the end "
"of parsed document %s", r->filename);
if (ctx->flags & SSI_FLAG_PRINTING) {
@@ -3481,7 +3746,7 @@ static apr_status_t send_parsed_content(ap_filter_t *f, apr_bucket_brigade *bb)
}
if (!(ctx->flags & SSI_FLAG_PRINTING)) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01373)
"missing closing endif directive in parsed document"
" %s", r->filename);
}
@@ -3534,7 +3799,7 @@ static int includes_setup(ap_filter_t *f)
* We don't know if we are going to be including a file or executing
* a program - in either case a strong ETag header will likely be invalid.
*/
- if (!conf->etag) {
+ if (conf->etag <= 0) {
apr_table_setn(f->r->notes, "no-etag", "");
}
@@ -3553,7 +3818,7 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
&include_module);
if (!(ap_allow_options(r) & OPT_INCLUDES)) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01374)
"mod_include: Options +Includes (or IncludesNoExec) "
"wasn't set, INCLUDES filter removed");
ap_remove_output_filter(f);
@@ -3565,6 +3830,7 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
/* create context for this filter */
f->ctx = ctx = apr_palloc(r->pool, sizeof(*ctx));
+ ctx->r = r;
ctx->intern = intern = apr_palloc(r->pool, sizeof(*ctx->intern));
ctx->pool = r->pool;
apr_pool_create(&ctx->dpool, ctx->pool);
@@ -3574,23 +3840,29 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
intern->seen_eos = 0;
intern->state = PARSE_PRE_HEAD;
ctx->flags = (SSI_FLAG_PRINTING | SSI_FLAG_COND_TRUE);
- if (ap_allow_options(r) & OPT_INCNOEXEC) {
+ if ((ap_allow_options(r) & OPT_INC_WITH_EXEC) == 0) {
ctx->flags |= SSI_FLAG_NO_EXEC;
}
- intern->accessenable = conf->accessenable;
+ intern->legacy_expr = (conf->legacy_expr > 0);
+ intern->expr_eval_ctx = NULL;
+ intern->expr_err = NULL;
+ intern->expr_vary_this = NULL;
ctx->if_nesting_level = 0;
intern->re = NULL;
- ctx->error_str = conf->default_error_msg;
- ctx->time_str = conf->default_time_fmt;
+ ctx->error_str = conf->default_error_msg ? conf->default_error_msg :
+ DEFAULT_ERROR_MSG;
+ ctx->time_str = conf->default_time_fmt ? conf->default_time_fmt :
+ DEFAULT_TIME_FORMAT;
intern->start_seq = sconf->default_start_tag;
intern->start_seq_pat = bndm_compile(ctx->pool, intern->start_seq,
strlen(intern->start_seq));
intern->end_seq = sconf->default_end_tag;
intern->end_seq_len = strlen(intern->end_seq);
- intern->undefined_echo = conf->undefined_echo;
- intern->undefined_echo_len = strlen(conf->undefined_echo);
+ intern->undefined_echo = conf->undefined_echo ? conf->undefined_echo :
+ DEFAULT_UNDEFINED_ECHO;
+ intern->undefined_echo_len = strlen(intern->undefined_echo);
}
if ((parent = ap_get_module_config(r->request_config, &include_module))) {
@@ -3634,7 +3906,7 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
*/
/* Must we respect the last modified header? By default, no */
- if (conf->lastmodified) {
+ if (conf->lastmodified > 0) {
/* update the last modified if we have a valid time, and only if
* we don't already have a valid last modified.
@@ -3648,7 +3920,9 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
}
/* Assure the platform supports Group protections */
- else if (((conf->xbithack == XBITHACK_FULL)
+ else if (((conf->xbithack == XBITHACK_FULL ||
+ (conf->xbithack == XBITHACK_UNSET &&
+ DEFAULT_XBITHACK == XBITHACK_FULL))
&& (r->finfo.valid & APR_FINFO_GPROT)
&& (r->finfo.protection & APR_GEXECUTE))) {
ap_update_mtime(r, r->finfo.mtime);
@@ -3673,10 +3947,6 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
static int include_fixup(request_rec *r)
{
- include_dir_config *conf;
-
- conf = ap_get_module_config(r->per_dir_config, &include_module);
-
if (r->handler && (strcmp(r->handler, "server-parsed") == 0))
{
if (!r->content_type || !*r->content_type) {
@@ -3692,7 +3962,13 @@ static int include_fixup(request_rec *r)
}
#else
{
- if (conf->xbithack == XBITHACK_OFF) {
+ include_dir_config *conf = ap_get_module_config(r->per_dir_config,
+ &include_module);
+
+ if (conf->xbithack == XBITHACK_OFF ||
+ (DEFAULT_XBITHACK == XBITHACK_OFF &&
+ conf->xbithack == XBITHACK_UNSET))
+ {
return DECLINED;
}
@@ -3700,7 +3976,7 @@ static int include_fixup(request_rec *r)
return DECLINED;
}
- if (!r->content_type || strcmp(r->content_type, "text/html")) {
+ if (!r->content_type || strncmp(r->content_type, "text/html", 9)) {
return DECLINED;
}
}
@@ -3724,19 +4000,32 @@ static int include_fixup(request_rec *r)
static void *create_includes_dir_config(apr_pool_t *p, char *dummy)
{
- include_dir_config *result = apr_palloc(p, sizeof(include_dir_config));
+ include_dir_config *result = apr_pcalloc(p, sizeof(include_dir_config));
- result->default_error_msg = DEFAULT_ERROR_MSG;
- result->default_time_fmt = DEFAULT_TIME_FORMAT;
- result->undefined_echo = DEFAULT_UNDEFINED_ECHO;
- result->xbithack = DEFAULT_XBITHACK;
- result->accessenable = DEFAULT_ACCESSENABLE;
- result->lastmodified = DEFAULT_LASTMODIFIED;
- result->etag = DEFAULT_ETAG;
+ result->xbithack = XBITHACK_UNSET;
+ result->lastmodified = UNSET;
+ result->etag = UNSET;
+ result->legacy_expr = UNSET;
return result;
}
+#define MERGE(b,o,n,val,unset) n->val = o->val != unset ? o->val : b->val
+static void *merge_includes_dir_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+ include_dir_config *base = (include_dir_config *)basev,
+ *over = (include_dir_config *)overridesv,
+ *new = apr_palloc(p, sizeof(include_dir_config));
+ MERGE(base, over, new, default_error_msg, NULL);
+ MERGE(base, over, new, default_time_fmt, NULL);
+ MERGE(base, over, new, undefined_echo, NULL);
+ MERGE(base, over, new, xbithack, XBITHACK_UNSET);
+ MERGE(base, over, new, lastmodified, UNSET);
+ MERGE(base, over, new, etag, UNSET);
+ MERGE(base, over, new, legacy_expr, UNSET);
+ return new;
+}
+
static void *create_includes_server_config(apr_pool_t *p, server_rec *server)
{
include_server_config *result;
@@ -3882,14 +4171,16 @@ static const command_rec includes_cmds[] =
"SSI End String Tag"),
AP_INIT_TAKE1("SSIUndefinedEcho", set_undefined_echo, NULL, OR_ALL,
"String to be displayed if an echoed variable is undefined"),
- AP_INIT_FLAG("SSIAccessEnable", ap_set_flag_slot,
- (void *)APR_OFFSETOF(include_dir_config, accessenable),
- OR_LIMIT, "Whether testing access is enabled. Limited to 'on' or 'off'"),
- AP_INIT_FLAG("SSILastModified", ap_set_flag_slot,
+ AP_INIT_FLAG("SSILegacyExprParser", ap_set_flag_slot_char,
+ (void *)APR_OFFSETOF(include_dir_config, legacy_expr),
+ OR_LIMIT,
+ "Whether to use the legacy expression parser compatible "
+ "with <= 2.2.x. Limited to 'on' or 'off'"),
+ AP_INIT_FLAG("SSILastModified", ap_set_flag_slot_char,
(void *)APR_OFFSETOF(include_dir_config, lastmodified),
OR_LIMIT, "Whether to set the last modified header or respect "
"an existing header. Limited to 'on' or 'off'"),
- AP_INIT_FLAG("SSIEtag", ap_set_flag_slot,
+ AP_INIT_FLAG("SSIEtag", ap_set_flag_slot_char,
(void *)APR_OFFSETOF(include_dir_config, etag),
OR_LIMIT, "Whether to allow the generation of ETags within the server. "
"Existing ETags will be preserved. Limited to 'on' or 'off'"),
@@ -3912,11 +4203,11 @@ static void register_hooks(apr_pool_t *p)
AP_FTYPE_RESOURCE);
}
-module AP_MODULE_DECLARE_DATA include_module =
+AP_DECLARE_MODULE(include) =
{
STANDARD20_MODULE_STUFF,
create_includes_dir_config, /* dir config creater */
- NULL, /* dir merger --- default is to override */
+ merge_includes_dir_config, /* dir config merger */
create_includes_server_config,/* server config */
NULL, /* merge server config */
includes_cmds, /* command apr_table_t */
diff --git a/modules/filters/mod_include.dep b/modules/filters/mod_include.dep
deleted file mode 100644
index 168b2b5e..00000000
--- a/modules/filters/mod_include.dep
+++ /dev/null
@@ -1,36 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_include.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_include.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.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\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_charset.h"\
- "..\..\include\util_ebcdic.h"\
- "..\..\include\util_filter.h"\
- "..\..\include\util_script.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_hash.h"\
- "..\..\srclib\apr\include\apr_lib.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_portable.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
- ".\mod_include.h"\
-
diff --git a/modules/filters/mod_include.h b/modules/filters/mod_include.h
index fd5621c0..73714a29 100644
--- a/modules/filters/mod_include.h
+++ b/modules/filters/mod_include.h
@@ -17,7 +17,7 @@
/**
* @file mod_include.h
* @brief Server Side Include Filter Extension Module for Apache
- *
+ *
* @defgroup MOD_INCLUDE mod_include
* @ingroup APACHE_MODS
* @{
@@ -94,8 +94,12 @@ typedef struct {
/* currently configured time format */
const char *time_str;
+ /* the current request */
+ request_rec *r;
+
/* pointer to internal (non-public) data, don't touch */
struct ssi_internal_ctx *intern;
+
} include_ctx_t;
typedef apr_status_t (include_handler_fn_t)(include_ctx_t *, ap_filter_t *,
@@ -109,7 +113,7 @@ APR_DECLARE_OPTIONAL_FN(char*, ap_ssi_parse_string,
(include_ctx_t *ctx, const char *in, char *out,
apr_size_t length, int leave_name));
-APR_DECLARE_OPTIONAL_FN(void, ap_register_include_handler,
+APR_DECLARE_OPTIONAL_FN(void, ap_register_include_handler,
(char *tag, include_handler_fn_t *func));
#endif /* MOD_INCLUDE */
diff --git a/modules/filters/mod_include.mak b/modules/filters/mod_include.mak
deleted file mode 100644
index 3ec38789..00000000
--- a/modules/filters/mod_include.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_include.dsp
-!IF "$(CFG)" == ""
-CFG=mod_include - Win32 Release
-!MESSAGE No configuration specified. Defaulting to mod_include - Win32 Release.
-!ENDIF
-
-!IF "$(CFG)" != "mod_include - Win32 Release" && "$(CFG)" != "mod_include - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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_include.mak" CFG="mod_include - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_include - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_include - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_include - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_include.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_include.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_include.obj"
- -@erase "$(INTDIR)\mod_include.res"
- -@erase "$(INTDIR)\mod_include_src.idb"
- -@erase "$(INTDIR)\mod_include_src.pdb"
- -@erase "$(OUTDIR)\mod_include.exp"
- -@erase "$(OUTDIR)\mod_include.lib"
- -@erase "$(OUTDIR)\mod_include.pdb"
- -@erase "$(OUTDIR)\mod_include.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_include_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_include.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_include.so" /d LONG_NAME="include_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_include.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_include.pdb" /debug /out:"$(OUTDIR)\mod_include.so" /implib:"$(OUTDIR)\mod_include.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_include.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_include.obj" \
- "$(INTDIR)\mod_include.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_include.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_include.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_include.so"
- if exist .\Release\mod_include.so.manifest mt.exe -manifest .\Release\mod_include.so.manifest -outputresource:.\Release\mod_include.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_include - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_include.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_include.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_include.obj"
- -@erase "$(INTDIR)\mod_include.res"
- -@erase "$(INTDIR)\mod_include_src.idb"
- -@erase "$(INTDIR)\mod_include_src.pdb"
- -@erase "$(OUTDIR)\mod_include.exp"
- -@erase "$(OUTDIR)\mod_include.lib"
- -@erase "$(OUTDIR)\mod_include.pdb"
- -@erase "$(OUTDIR)\mod_include.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_include_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_include.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_include.so" /d LONG_NAME="include_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_include.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_include.pdb" /debug /out:"$(OUTDIR)\mod_include.so" /implib:"$(OUTDIR)\mod_include.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_include.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_include.obj" \
- "$(INTDIR)\mod_include.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_include.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_include.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_include.so"
- if exist .\Debug\mod_include.so.manifest mt.exe -manifest .\Debug\mod_include.so.manifest -outputresource:.\Debug\mod_include.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_include.dep")
-!INCLUDE "mod_include.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_include.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_include - Win32 Release" || "$(CFG)" == "mod_include - Win32 Debug"
-
-!IF "$(CFG)" == "mod_include - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_include - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_include - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_include - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_include - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_include - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_include - Win32 Release"
-
-
-"$(INTDIR)\mod_include.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_include.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_include.so" /d LONG_NAME="include_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_include - Win32 Debug"
-
-
-"$(INTDIR)\mod_include.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_include.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_include.so" /d LONG_NAME="include_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_include.c
-
-"$(INTDIR)\mod_include.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_proxy_html.c b/modules/filters/mod_proxy_html.c
new file mode 100644
index 00000000..a1c5fbfb
--- /dev/null
+++ b/modules/filters/mod_proxy_html.c
@@ -0,0 +1,1266 @@
+/* Copyright (c) 2003-11, WebThing Ltd
+ * Copyright (c) 2011-, The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/* GO_FASTER
+ You can #define GO_FASTER to disable trace logging.
+*/
+
+#ifdef GO_FASTER
+#define VERBOSE(x)
+#define VERBOSEB(x)
+#else
+#define VERBOSE(x) if (verbose) x
+#define VERBOSEB(x) if (verbose) {x}
+#endif
+
+#include <ctype.h>
+
+/* libxml2 */
+#include <libxml/HTMLparser.h>
+
+#include "http_protocol.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "apr_strings.h"
+#include "apr_hash.h"
+#include "apr_strmatch.h"
+
+#include "apr_optional.h"
+#include "mod_xml2enc.h"
+#include "http_request.h"
+#include "ap_expr.h"
+
+/* globals set once at startup */
+static ap_rxplus_t* old_expr;
+static ap_regex_t* seek_meta;
+static const apr_strmatch_pattern* seek_content;
+static apr_status_t (*xml2enc_charset)(request_rec*, xmlCharEncoding*, const char**) = NULL;
+static apr_status_t (*xml2enc_filter)(request_rec*, const char*, unsigned int) = NULL;
+
+module AP_MODULE_DECLARE_DATA proxy_html_module;
+
+#define M_HTML 0x01
+#define M_EVENTS 0x02
+#define M_CDATA 0x04
+#define M_REGEX 0x08
+#define M_ATSTART 0x10
+#define M_ATEND 0x20
+#define M_LAST 0x40
+#define M_NOTLAST 0x80
+#define M_INTERPOLATE_TO 0x100
+#define M_INTERPOLATE_FROM 0x200
+
+typedef struct {
+ const char* val;
+} tattr;
+typedef struct {
+ unsigned int start;
+ unsigned int end;
+} meta;
+typedef struct urlmap {
+ struct urlmap* next;
+ unsigned int flags;
+ unsigned int regflags;
+ union {
+ const char* c;
+ ap_regex_t* r;
+ } from;
+ const char* to;
+ ap_expr_info_t *cond;
+} urlmap;
+typedef struct {
+ urlmap* map;
+ const char* doctype;
+ const char* etag;
+ unsigned int flags;
+ size_t bufsz;
+ apr_hash_t* links;
+ apr_array_header_t* events;
+ const char* charset_out;
+ int extfix;
+ int metafix;
+ int strip_comments;
+ int interp;
+ int enabled;
+} proxy_html_conf;
+typedef struct {
+ ap_filter_t* f;
+ proxy_html_conf* cfg;
+ htmlParserCtxtPtr parser;
+ apr_bucket_brigade* bb;
+ char* buf;
+ size_t offset;
+ size_t avail;
+ const char* encoding;
+ urlmap* map;
+} saxctxt;
+
+
+#define NORM_LC 0x1
+#define NORM_MSSLASH 0x2
+#define NORM_RESET 0x4
+static htmlSAXHandler sax;
+
+typedef enum { ATTR_IGNORE, ATTR_URI, ATTR_EVENT } rewrite_t;
+
+static const char* const fpi_html =
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n";
+static const char* const fpi_html_legacy =
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
+static const char* const fpi_xhtml =
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
+static const char* const fpi_xhtml_legacy =
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
+static const char* const html_etag = ">";
+static const char* const xhtml_etag = " />";
+/*#define DEFAULT_DOCTYPE fpi_html */
+static const char* const DEFAULT_DOCTYPE = "";
+#define DEFAULT_ETAG html_etag
+
+static void normalise(unsigned int flags, char* str)
+{
+ char* p;
+ if (flags & NORM_LC)
+ for (p = str; *p; ++p)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (flags & NORM_MSSLASH)
+ for (p = ap_strchr(str, '\\'); p; p = ap_strchr(p+1, '\\'))
+ *p = '/';
+
+}
+#define consume_buffer(ctx,inbuf,bytes,flag) \
+ htmlParseChunk(ctx->parser, inbuf, bytes, flag)
+
+#define AP_fwrite(ctx,inbuf,bytes,flush) \
+ ap_fwrite(ctx->f->next, ctx->bb, inbuf, bytes);
+
+/* This is always utf-8 on entry. We can convert charset within FLUSH */
+#define FLUSH AP_fwrite(ctx, (chars+begin), (i-begin), 0); begin = i+1
+static void pcharacters(void* ctxt, const xmlChar *uchars, int length)
+{
+ const char* chars = (const char*) uchars;
+ saxctxt* ctx = (saxctxt*) ctxt;
+ int i;
+ int begin;
+ for (begin=i=0; i<length; i++) {
+ switch (chars[i]) {
+ case '&' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&amp;"); break;
+ case '<' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&lt;"); break;
+ case '>' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&gt;"); break;
+ case '"' : FLUSH; ap_fputs(ctx->f->next, ctx->bb, "&quot;"); break;
+ default : break;
+ }
+ }
+ FLUSH;
+}
+static void preserve(saxctxt* ctx, const size_t len)
+{
+ char* newbuf;
+ if (len <= (ctx->avail - ctx->offset))
+ return;
+ else while (len > (ctx->avail - ctx->offset))
+ ctx->avail += ctx->cfg->bufsz;
+
+ newbuf = realloc(ctx->buf, ctx->avail);
+ if (newbuf != ctx->buf) {
+ if (ctx->buf)
+ apr_pool_cleanup_kill(ctx->f->r->pool, ctx->buf,
+ (int(*)(void*))free);
+ apr_pool_cleanup_register(ctx->f->r->pool, newbuf,
+ (int(*)(void*))free, apr_pool_cleanup_null);
+ ctx->buf = newbuf;
+ }
+}
+static void pappend(saxctxt* ctx, const char* buf, const size_t len)
+{
+ preserve(ctx, len);
+ memcpy(ctx->buf+ctx->offset, buf, len);
+ ctx->offset += len;
+}
+static void dump_content(saxctxt* ctx)
+{
+ urlmap* m;
+ char* found;
+ size_t s_from, s_to;
+ size_t match;
+ char c = 0;
+ int nmatch;
+ ap_regmatch_t pmatch[10];
+ char* subs;
+ size_t len, offs;
+ urlmap* themap = ctx->map;
+#ifndef GO_FASTER
+ int verbose = APLOGrtrace1(ctx->f->r);
+#endif
+
+ pappend(ctx, &c, 1); /* append null byte */
+ /* parse the text for URLs */
+ for (m = themap; m; m = m->next) {
+ if (!(m->flags & M_CDATA))
+ continue;
+ if (m->flags & M_REGEX) {
+ nmatch = 10;
+ offs = 0;
+ while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) {
+ match = pmatch[0].rm_so;
+ s_from = pmatch[0].rm_eo - match;
+ subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
+ nmatch, pmatch);
+ s_to = strlen(subs);
+ len = strlen(ctx->buf);
+ offs += match;
+ VERBOSEB(
+ const char* f = apr_pstrndup(ctx->f->r->pool,
+ ctx->buf + offs, s_from);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
+ "C/RX: match at %s, substituting %s", f, subs);
+ )
+ if (s_to > s_from) {
+ preserve(ctx, s_to - s_from);
+ memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
+ len + 1 - s_from - offs);
+ memcpy(ctx->buf+offs, subs, s_to);
+ }
+ else {
+ memcpy(ctx->buf + offs, subs, s_to);
+ memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from,
+ len + 1 - s_from - offs);
+ }
+ offs += s_to;
+ }
+ }
+ else {
+ s_from = strlen(m->from.c);
+ s_to = strlen(m->to);
+ for (found = strstr(ctx->buf, m->from.c); found;
+ found = strstr(ctx->buf+match+s_to, m->from.c)) {
+ match = found - ctx->buf;
+ if ((m->flags & M_ATSTART) && (match != 0))
+ break;
+ len = strlen(ctx->buf);
+ if ((m->flags & M_ATEND) && (match < (len - s_from)))
+ continue;
+ VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r,
+ "C: matched %s, substituting %s",
+ m->from.c, m->to));
+ if (s_to > s_from) {
+ preserve(ctx, s_to - s_from);
+ memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
+ len + 1 - s_from - match);
+ memcpy(ctx->buf+match, m->to, s_to);
+ }
+ else {
+ memcpy(ctx->buf+match, m->to, s_to);
+ memmove(ctx->buf+match+s_to, ctx->buf+match+s_from,
+ len + 1 - s_from - match);
+ }
+ }
+ }
+ }
+ AP_fwrite(ctx, ctx->buf, strlen(ctx->buf), 1);
+}
+static void pcdata(void* ctxt, const xmlChar *uchars, int length)
+{
+ const char* chars = (const char*) uchars;
+ saxctxt* ctx = (saxctxt*) ctxt;
+ if (ctx->cfg->extfix) {
+ pappend(ctx, chars, length);
+ }
+ else {
+ /* not sure if this should force-flush
+ * (i.e. can one cdata section come in multiple calls?)
+ */
+ AP_fwrite(ctx, chars, length, 0);
+ }
+}
+static void pcomment(void* ctxt, const xmlChar *uchars)
+{
+ const char* chars = (const char*) uchars;
+ saxctxt* ctx = (saxctxt*) ctxt;
+ if (ctx->cfg->strip_comments)
+ return;
+
+ if (ctx->cfg->extfix) {
+ pappend(ctx, "<!--", 4);
+ pappend(ctx, chars, strlen(chars));
+ pappend(ctx, "-->", 3);
+ }
+ else {
+ ap_fputs(ctx->f->next, ctx->bb, "<!--");
+ AP_fwrite(ctx, chars, strlen(chars), 1);
+ ap_fputs(ctx->f->next, ctx->bb, "-->");
+ }
+}
+static void pendElement(void* ctxt, const xmlChar* uname)
+{
+ saxctxt* ctx = (saxctxt*) ctxt;
+ const char* name = (const char*) uname;
+ const htmlElemDesc* desc = htmlTagLookup(uname);
+
+ if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
+ /* enforce html */
+ if (!desc || desc->depr)
+ return;
+
+ }
+ else if ((ctx->cfg->doctype == fpi_html)
+ || (ctx->cfg->doctype == fpi_xhtml)) {
+ /* enforce html legacy */
+ if (!desc)
+ return;
+ }
+ /* TODO - implement HTML "allowed here" using the stack */
+ /* nah. Keeping the stack is too much overhead */
+
+ if (ctx->offset > 0) {
+ dump_content(ctx);
+ ctx->offset = 0; /* having dumped it, we can re-use the memory */
+ }
+ if (!desc || !desc->empty) {
+ ap_fprintf(ctx->f->next, ctx->bb, "</%s>", name);
+ }
+}
+static void pstartElement(void* ctxt, const xmlChar* uname,
+ const xmlChar** uattrs)
+{
+ int required_attrs;
+ int num_match;
+ size_t offs, len;
+ char* subs;
+ rewrite_t is_uri;
+ const char** a;
+ urlmap* m;
+ size_t s_to, s_from, match;
+ char* found;
+ saxctxt* ctx = (saxctxt*) ctxt;
+ size_t nmatch;
+ ap_regmatch_t pmatch[10];
+#ifndef GO_FASTER
+ int verbose = APLOGrtrace1(ctx->f->r);
+#endif
+ apr_array_header_t *linkattrs;
+ int i;
+ const char* name = (const char*) uname;
+ const char** attrs = (const char**) uattrs;
+ const htmlElemDesc* desc = htmlTagLookup(uname);
+ urlmap* themap = ctx->map;
+#ifdef HAVE_STACK
+ const void** descp;
+#endif
+ int enforce = 0;
+ if ((ctx->cfg->doctype == fpi_html) || (ctx->cfg->doctype == fpi_xhtml)) {
+ /* enforce html */
+ enforce = 2;
+ if (!desc || desc->depr)
+ return;
+
+ }
+ else if ((ctx->cfg->doctype == fpi_html)
+ || (ctx->cfg->doctype == fpi_xhtml)) {
+ enforce = 1;
+ /* enforce html legacy */
+ if (!desc) {
+ return;
+ }
+ }
+ if (!desc && enforce) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01416)
+ "Bogus HTML element %s dropped", name);
+ return;
+ }
+ if (desc && desc->depr && (enforce == 2)) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01417)
+ "Deprecated HTML element %s dropped", name);
+ return;
+ }
+#ifdef HAVE_STACK
+ descp = apr_array_push(ctx->stack);
+ *descp = desc;
+ /* TODO - implement HTML "allowed here" */
+#endif
+
+ ap_fputc(ctx->f->next, ctx->bb, '<');
+ ap_fputs(ctx->f->next, ctx->bb, name);
+
+ required_attrs = 0;
+ if ((enforce > 0) && (desc != NULL) && (desc->attrs_req != NULL))
+ for (a = desc->attrs_req; *a; a++)
+ ++required_attrs;
+
+ if (attrs) {
+ linkattrs = apr_hash_get(ctx->cfg->links, name, APR_HASH_KEY_STRING);
+ for (a = attrs; *a; a += 2) {
+ if (desc && enforce > 0) {
+ switch (htmlAttrAllowed(desc, (xmlChar*)*a, 2-enforce)) {
+ case HTML_INVALID:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01418)
+ "Bogus HTML attribute %s of %s dropped",
+ *a, name);
+ continue;
+ case HTML_DEPRECATED:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01419)
+ "Deprecated HTML attribute %s of %s dropped",
+ *a, name);
+ continue;
+ case HTML_REQUIRED:
+ required_attrs--; /* cross off the number still needed */
+ /* fallthrough - required implies valid */
+ default:
+ break;
+ }
+ }
+ ctx->offset = 0;
+ if (a[1]) {
+ pappend(ctx, a[1], strlen(a[1])+1);
+ is_uri = ATTR_IGNORE;
+ if (linkattrs) {
+ tattr* attrs = (tattr*) linkattrs->elts;
+ for (i=0; i < linkattrs->nelts; ++i) {
+ if (!strcmp(*a, attrs[i].val)) {
+ is_uri = ATTR_URI;
+ break;
+ }
+ }
+ }
+ if ((is_uri == ATTR_IGNORE) && ctx->cfg->extfix
+ && (ctx->cfg->events != NULL)) {
+ for (i=0; i < ctx->cfg->events->nelts; ++i) {
+ tattr* attrs = (tattr*) ctx->cfg->events->elts;
+ if (!strcmp(*a, attrs[i].val)) {
+ is_uri = ATTR_EVENT;
+ break;
+ }
+ }
+ }
+ switch (is_uri) {
+ case ATTR_URI:
+ num_match = 0;
+ for (m = themap; m; m = m->next) {
+ if (!(m->flags & M_HTML))
+ continue;
+ if (m->flags & M_REGEX) {
+ nmatch = 10;
+ if (!ap_regexec(m->from.r, ctx->buf, nmatch,
+ pmatch, 0)) {
+ ++num_match;
+ offs = match = pmatch[0].rm_so;
+ s_from = pmatch[0].rm_eo - match;
+ subs = ap_pregsub(ctx->f->r->pool, m->to,
+ ctx->buf, nmatch, pmatch);
+ VERBOSE({
+ const char* f;
+ f = apr_pstrndup(ctx->f->r->pool,
+ ctx->buf + offs, s_from);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0,
+ ctx->f->r,
+ "H/RX: match at %s, substituting %s",
+ f, subs);
+ })
+ s_to = strlen(subs);
+ len = strlen(ctx->buf);
+ if (s_to > s_from) {
+ preserve(ctx, s_to - s_from);
+ memmove(ctx->buf+offs+s_to,
+ ctx->buf+offs+s_from,
+ len + 1 - s_from - offs);
+ memcpy(ctx->buf+offs, subs, s_to);
+ }
+ else {
+ memcpy(ctx->buf + offs, subs, s_to);
+ memmove(ctx->buf+offs+s_to,
+ ctx->buf+offs+s_from,
+ len + 1 - s_from - offs);
+ }
+ }
+ } else {
+ s_from = strlen(m->from.c);
+ if (!strncasecmp(ctx->buf, m->from.c, s_from)) {
+ ++num_match;
+ s_to = strlen(m->to);
+ len = strlen(ctx->buf);
+ VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3,
+ 0, ctx->f->r,
+ "H: matched %s, substituting %s",
+ m->from.c, m->to));
+ if (s_to > s_from) {
+ preserve(ctx, s_to - s_from);
+ memmove(ctx->buf+s_to, ctx->buf+s_from,
+ len + 1 - s_from);
+ memcpy(ctx->buf, m->to, s_to);
+ }
+ else { /* it fits in the existing space */
+ memcpy(ctx->buf, m->to, s_to);
+ memmove(ctx->buf+s_to, ctx->buf+s_from,
+ len + 1 - s_from);
+ }
+ break;
+ }
+ }
+ /* URIs only want one match unless overridden in the config */
+ if ((num_match > 0) && !(m->flags & M_NOTLAST))
+ break;
+ }
+ break;
+ case ATTR_EVENT:
+ for (m = themap; m; m = m->next) {
+ num_match = 0; /* reset here since we're working per-rule */
+ if (!(m->flags & M_EVENTS))
+ continue;
+ if (m->flags & M_REGEX) {
+ nmatch = 10;
+ offs = 0;
+ while (!ap_regexec(m->from.r, ctx->buf+offs,
+ nmatch, pmatch, 0)) {
+ match = pmatch[0].rm_so;
+ s_from = pmatch[0].rm_eo - match;
+ subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs,
+ nmatch, pmatch);
+ VERBOSE({
+ const char* f;
+ f = apr_pstrndup(ctx->f->r->pool,
+ ctx->buf + offs, s_from);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0,
+ ctx->f->r,
+ "E/RX: match at %s, substituting %s",
+ f, subs);
+ })
+ s_to = strlen(subs);
+ offs += match;
+ len = strlen(ctx->buf);
+ if (s_to > s_from) {
+ preserve(ctx, s_to - s_from);
+ memmove(ctx->buf+offs+s_to,
+ ctx->buf+offs+s_from,
+ len + 1 - s_from - offs);
+ memcpy(ctx->buf+offs, subs, s_to);
+ }
+ else {
+ memcpy(ctx->buf + offs, subs, s_to);
+ memmove(ctx->buf+offs+s_to,
+ ctx->buf+offs+s_from,
+ len + 1 - s_from - offs);
+ }
+ offs += s_to;
+ ++num_match;
+ }
+ }
+ else {
+ found = strstr(ctx->buf, m->from.c);
+ if ((m->flags & M_ATSTART) && (found != ctx->buf))
+ continue;
+ while (found) {
+ s_from = strlen(m->from.c);
+ s_to = strlen(m->to);
+ match = found - ctx->buf;
+ if ((s_from < strlen(found))
+ && (m->flags & M_ATEND)) {
+ found = strstr(ctx->buf+match+s_from,
+ m->from.c);
+ continue;
+ }
+ else {
+ found = strstr(ctx->buf+match+s_to,
+ m->from.c);
+ }
+ VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3,
+ 0, ctx->f->r,
+ "E: matched %s, substituting %s",
+ m->from.c, m->to));
+ len = strlen(ctx->buf);
+ if (s_to > s_from) {
+ preserve(ctx, s_to - s_from);
+ memmove(ctx->buf+match+s_to,
+ ctx->buf+match+s_from,
+ len + 1 - s_from - match);
+ memcpy(ctx->buf+match, m->to, s_to);
+ }
+ else {
+ memcpy(ctx->buf+match, m->to, s_to);
+ memmove(ctx->buf+match+s_to,
+ ctx->buf+match+s_from,
+ len + 1 - s_from - match);
+ }
+ ++num_match;
+ }
+ }
+ if (num_match && (m->flags & M_LAST))
+ break;
+ }
+ break;
+ case ATTR_IGNORE:
+ break;
+ }
+ }
+ if (!a[1])
+ ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], NULL);
+ else {
+
+ if (ctx->cfg->flags != 0)
+ normalise(ctx->cfg->flags, ctx->buf);
+
+ /* write the attribute, using pcharacters to html-escape
+ anything that needs it in the value.
+ */
+ ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL);
+ pcharacters(ctx, (const xmlChar*)ctx->buf, strlen(ctx->buf));
+ ap_fputc(ctx->f->next, ctx->bb, '"');
+ }
+ }
+ }
+ ctx->offset = 0;
+ if (desc && desc->empty)
+ ap_fputs(ctx->f->next, ctx->bb, ctx->cfg->etag);
+ else
+ ap_fputc(ctx->f->next, ctx->bb, '>');
+
+ if ((enforce > 0) && (required_attrs > 0)) {
+ /* if there are more required attributes than we found then complain */
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ctx->f->r, APLOGNO(01420)
+ "HTML element %s is missing %d required attributes",
+ name, required_attrs);
+ }
+}
+
+static meta* metafix(request_rec* r, const char* buf)
+{
+ meta* ret = NULL;
+ size_t offs = 0;
+ const char* p;
+ const char* q;
+ char* header;
+ char* content;
+ ap_regmatch_t pmatch[2];
+ char delim;
+
+ while (!ap_regexec(seek_meta, buf+offs, 2, pmatch, 0)) {
+ header = NULL;
+ content = NULL;
+ p = buf+offs+pmatch[1].rm_eo;
+ while (!isalpha(*++p));
+ for (q = p; isalnum(*q) || (*q == '-'); ++q);
+ header = apr_pstrndup(r->pool, p, q-p);
+ if (strncasecmp(header, "Content-", 8)) {
+ /* find content=... string */
+ p = apr_strmatch(seek_content, buf+offs+pmatch[0].rm_so,
+ pmatch[0].rm_eo - pmatch[0].rm_so);
+ /* if it doesn't contain "content", ignore, don't crash! */
+ if (p != NULL) {
+ while (*p) {
+ p += 7;
+ while (*p && isspace(*p))
+ ++p;
+ if (*p != '=')
+ continue;
+ while (*p && isspace(*++p));
+ if ((*p == '\'') || (*p == '"')) {
+ delim = *p++;
+ for (q = p; *q != delim; ++q);
+ } else {
+ for (q = p; *q && !isspace(*q) && (*q != '>'); ++q);
+ }
+ content = apr_pstrndup(r->pool, p, q-p);
+ break;
+ }
+ }
+ }
+ else if (!strncasecmp(header, "Content-Type", 12)) {
+ ret = apr_palloc(r->pool, sizeof(meta));
+ ret->start = pmatch[0].rm_so;
+ ret->end = pmatch[0].rm_eo;
+ }
+ if (header && content) {
+#ifndef GO_FASTER
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "Adding header [%s: %s] from HTML META",
+ header, content);
+#endif
+ apr_table_setn(r->headers_out, header, content);
+ }
+ offs += pmatch[0].rm_eo;
+ }
+ return ret;
+}
+
+static const char* interpolate_vars(request_rec* r, const char* str)
+{
+ const char* start;
+ const char* end;
+ const char* delim;
+ const char* before;
+ const char* after;
+ const char* replacement;
+ const char* var;
+ for (;;) {
+ start = str;
+ if (start = ap_strstr_c(start, "${"), start == NULL)
+ break;
+
+ if (end = ap_strchr_c(start+2, '}'), end == NULL)
+ break;
+
+ delim = ap_strchr_c(start, '|');
+ before = apr_pstrndup(r->pool, str, start-str);
+ after = end+1;
+ if (delim) {
+ var = apr_pstrndup(r->pool, start+2, delim-start-2);
+ }
+ else {
+ var = apr_pstrndup(r->pool, start+2, end-start-2);
+ }
+ replacement = apr_table_get(r->subprocess_env, var);
+ if (!replacement) {
+ if (delim)
+ replacement = apr_pstrndup(r->pool, delim+1, end-delim-1);
+ else
+ replacement = "";
+ }
+ str = apr_pstrcat(r->pool, before, replacement, after, NULL);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Interpolating %s => %s", var, replacement);
+ }
+ return str;
+}
+static void fixup_rules(saxctxt* ctx)
+{
+ urlmap* newp;
+ urlmap* p;
+ urlmap* prev = NULL;
+ request_rec* r = ctx->f->r;
+
+ for (p = ctx->cfg->map; p; p = p->next) {
+ if (p->cond != NULL) {
+ const char *err;
+ int ok = ap_expr_exec(r, p->cond, &err);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01421)
+ "Error evaluating expr: %s", err);
+ }
+ if (ok == 0) {
+ continue; /* condition is unsatisfied */
+ }
+ }
+
+ newp = apr_pmemdup(r->pool, p, sizeof(urlmap));
+
+ if (newp->flags & M_INTERPOLATE_FROM) {
+ newp->from.c = interpolate_vars(r, newp->from.c);
+ if (!newp->from.c || !*newp->from.c)
+ continue; /* don't use empty from-pattern */
+ if (newp->flags & M_REGEX) {
+ newp->from.r = ap_pregcomp(r->pool, newp->from.c,
+ newp->regflags);
+ }
+ }
+ if (newp->flags & M_INTERPOLATE_TO) {
+ newp->to = interpolate_vars(r, newp->to);
+ }
+ /* evaluate p->cond; continue if unsatisfied */
+ /* create new urlmap with memcpy and append to map */
+ /* interpolate from if flagged to do so */
+ /* interpolate to if flagged to do so */
+
+ if (prev != NULL)
+ prev->next = newp;
+ else
+ ctx->map = newp;
+ prev = newp;
+ }
+
+ if (prev)
+ prev->next = NULL;
+}
+static saxctxt* check_filter_init (ap_filter_t* f)
+{
+ saxctxt* fctx;
+ if (!f->ctx) {
+ proxy_html_conf* cfg;
+ const char* force;
+ const char* errmsg = NULL;
+ cfg = ap_get_module_config(f->r->per_dir_config, &proxy_html_module);
+ force = apr_table_get(f->r->subprocess_env, "PROXY_HTML_FORCE");
+
+ if (!force) {
+ if (!f->r->proxyreq) {
+ errmsg = "Non-proxy request; not inserting proxy-html filter";
+ }
+ else if (!f->r->content_type) {
+ errmsg = "No content-type; bailing out of proxy-html filter";
+ }
+ else if (strncasecmp(f->r->content_type, "text/html", 9) &&
+ strncasecmp(f->r->content_type,
+ "application/xhtml+xml", 21)) {
+ errmsg = "Non-HTML content; not inserting proxy-html filter";
+ }
+ }
+ if (!cfg->links) {
+ errmsg = "No links configured: nothing for proxy-html filter to do";
+ }
+
+ if (errmsg) {
+#ifndef GO_FASTER
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r, "%s", errmsg);
+#endif
+ ap_remove_output_filter(f);
+ return NULL;
+ }
+
+ fctx = f->ctx = apr_pcalloc(f->r->pool, sizeof(saxctxt));
+ fctx->f = f;
+ fctx->bb = apr_brigade_create(f->r->pool,
+ f->r->connection->bucket_alloc);
+ fctx->cfg = cfg;
+ apr_table_unset(f->r->headers_out, "Content-Length");
+
+ if (cfg->interp)
+ fixup_rules(fctx);
+ else
+ fctx->map = cfg->map;
+ /* defer dealing with charset_out until after sniffing charset_in
+ * so we can support setting one to t'other.
+ */
+ }
+ return f->ctx;
+}
+static int proxy_html_filter(ap_filter_t* f, apr_bucket_brigade* bb)
+{
+ apr_bucket* b;
+ meta* m = NULL;
+ xmlCharEncoding enc;
+ const char* buf = 0;
+ apr_size_t bytes = 0;
+#ifndef USE_OLD_LIBXML2
+ int xmlopts = XML_PARSE_RECOVER | XML_PARSE_NONET |
+ XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
+#endif
+
+ saxctxt* ctxt = check_filter_init(f);
+ if (!ctxt)
+ return ap_pass_brigade(f->next, bb);
+ for (b = APR_BRIGADE_FIRST(bb);
+ b != APR_BRIGADE_SENTINEL(bb);
+ b = APR_BUCKET_NEXT(b)) {
+ if (APR_BUCKET_IS_METADATA(b)) {
+ if (APR_BUCKET_IS_EOS(b)) {
+ if (ctxt->parser != NULL) {
+ consume_buffer(ctxt, buf, 0, 1);
+ }
+ APR_BRIGADE_INSERT_TAIL(ctxt->bb,
+ apr_bucket_eos_create(ctxt->bb->bucket_alloc));
+ ap_pass_brigade(ctxt->f->next, ctxt->bb);
+ }
+ else if (APR_BUCKET_IS_FLUSH(b)) {
+ /* pass on flush, except at start where it would cause
+ * headers to be sent before doc sniffing
+ */
+ if (ctxt->parser != NULL) {
+ ap_fflush(ctxt->f->next, ctxt->bb);
+ }
+ }
+ }
+ else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
+ == APR_SUCCESS) {
+ if (ctxt->parser == NULL) {
+ const char* cenc;
+ if (!xml2enc_charset ||
+ (xml2enc_charset(f->r, &enc, &cenc) != APR_SUCCESS)) {
+ if (!xml2enc_charset)
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01422)
+ "No i18n support found. Install mod_xml2enc if required");
+ enc = XML_CHAR_ENCODING_NONE;
+ ap_set_content_type(f->r, "text/html;charset=utf-8");
+ }
+ else {
+ /* if we wanted a non-default charset_out, insert the
+ * xml2enc filter now that we've sniffed it
+ */
+ if (ctxt->cfg->charset_out && xml2enc_filter) {
+ if (*ctxt->cfg->charset_out != '*')
+ cenc = ctxt->cfg->charset_out;
+ xml2enc_filter(f->r, cenc, ENCIO_OUTPUT);
+ ap_set_content_type(f->r,
+ apr_pstrcat(f->r->pool,
+ "text/html;charset=",
+ cenc, NULL));
+ }
+ else /* Normal case, everything worked, utf-8 output */
+ ap_set_content_type(f->r, "text/html;charset=utf-8");
+ }
+
+ ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
+ ctxt->parser = htmlCreatePushParserCtxt(&sax, ctxt, buf,
+ 4, 0, enc);
+ buf += 4;
+ bytes -= 4;
+ if (ctxt->parser == NULL) {
+ apr_status_t rv = ap_pass_brigade(f->next, bb);
+ ap_remove_output_filter(f);
+ return rv;
+ }
+ apr_pool_cleanup_register(f->r->pool, ctxt->parser,
+ (int(*)(void*))htmlFreeParserCtxt,
+ apr_pool_cleanup_null);
+#ifndef USE_OLD_LIBXML2
+ if (xmlopts = xmlCtxtUseOptions(ctxt->parser, xmlopts), xmlopts)
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01423)
+ "Unsupported parser opts %x", xmlopts);
+#endif
+ if (ctxt->cfg->metafix)
+ m = metafix(f->r, buf);
+ if (m) {
+ consume_buffer(ctxt, buf, m->start, 0);
+ consume_buffer(ctxt, buf+m->end, bytes-m->end, 0);
+ }
+ else {
+ consume_buffer(ctxt, buf, bytes, 0);
+ }
+ }
+ else {
+ consume_buffer(ctxt, buf, bytes, 0);
+ }
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01424)
+ "Error in bucket read");
+ }
+ }
+ /*ap_fflush(ctxt->f->next, ctxt->bb); // uncomment for debug */
+ apr_brigade_cleanup(bb);
+ return APR_SUCCESS;
+}
+
+static void* proxy_html_config(apr_pool_t* pool, char* x)
+{
+ proxy_html_conf* ret = apr_pcalloc(pool, sizeof(proxy_html_conf));
+ ret->doctype = DEFAULT_DOCTYPE;
+ ret->etag = DEFAULT_ETAG;
+ ret->bufsz = 8192;
+ /* ret->interp = 1; */
+ /* don't initialise links and events until they get set/used */
+ return ret;
+}
+static void* proxy_html_merge(apr_pool_t* pool, void* BASE, void* ADD)
+{
+ proxy_html_conf* base = (proxy_html_conf*) BASE;
+ proxy_html_conf* add = (proxy_html_conf*) ADD;
+ proxy_html_conf* conf = apr_palloc(pool, sizeof(proxy_html_conf));
+
+ /* don't merge declarations - just use the most specific */
+ conf->links = (add->links == NULL) ? base->links : add->links;
+ conf->events = (add->events == NULL) ? base->events : add->events;
+
+ conf->charset_out = (add->charset_out == NULL)
+ ? base->charset_out : add->charset_out;
+
+ if (add->map && base->map) {
+ urlmap* a;
+ conf->map = NULL;
+ for (a = base->map; a; a = a->next) {
+ urlmap* save = conf->map;
+ conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
+ conf->map->next = save;
+ }
+ for (a = add->map; a; a = a->next) {
+ urlmap* save = conf->map;
+ conf->map = apr_pmemdup(pool, a, sizeof(urlmap));
+ conf->map->next = save;
+ }
+ }
+ else
+ conf->map = add->map ? add->map : base->map;
+
+ conf->doctype = (add->doctype == DEFAULT_DOCTYPE)
+ ? base->doctype : add->doctype;
+ conf->etag = (add->etag == DEFAULT_ETAG) ? base->etag : add->etag;
+ conf->bufsz = add->bufsz;
+ if (add->flags & NORM_RESET) {
+ conf->flags = add->flags ^ NORM_RESET;
+ conf->metafix = add->metafix;
+ conf->extfix = add->extfix;
+ conf->interp = add->interp;
+ conf->strip_comments = add->strip_comments;
+ conf->enabled = add->enabled;
+ }
+ else {
+ conf->flags = base->flags | add->flags;
+ conf->metafix = base->metafix | add->metafix;
+ conf->extfix = base->extfix | add->extfix;
+ conf->interp = base->interp | add->interp;
+ conf->strip_comments = base->strip_comments | add->strip_comments;
+ conf->enabled = add->enabled | base->enabled;
+ }
+ return conf;
+}
+#define REGFLAG(n,s,c) ((s&&(ap_strchr_c((s),(c))!=NULL)) ? (n) : 0)
+#define XREGFLAG(n,s,c) ((!s||(ap_strchr_c((s),(c))==NULL)) ? (n) : 0)
+static const char* comp_urlmap(cmd_parms *cmd, urlmap* newmap,
+ const char* from, const char* to,
+ const char* flags, const char* cond)
+{
+ const char *err = NULL;
+ newmap->flags
+ = XREGFLAG(M_HTML,flags,'h')
+ | XREGFLAG(M_EVENTS,flags,'e')
+ | XREGFLAG(M_CDATA,flags,'c')
+ | REGFLAG(M_ATSTART,flags,'^')
+ | REGFLAG(M_ATEND,flags,'$')
+ | REGFLAG(M_REGEX,flags,'R')
+ | REGFLAG(M_LAST,flags,'L')
+ | REGFLAG(M_NOTLAST,flags,'l')
+ | REGFLAG(M_INTERPOLATE_TO,flags,'V')
+ | REGFLAG(M_INTERPOLATE_FROM,flags,'v');
+
+ if ((newmap->flags & M_INTERPOLATE_FROM) || !(newmap->flags & M_REGEX)) {
+ newmap->from.c = from;
+ newmap->to = to;
+ }
+ else {
+ newmap->regflags
+ = REGFLAG(AP_REG_EXTENDED,flags,'x')
+ | REGFLAG(AP_REG_ICASE,flags,'i')
+ | REGFLAG(AP_REG_NOSUB,flags,'n')
+ | REGFLAG(AP_REG_NEWLINE,flags,'s');
+ newmap->from.r = ap_pregcomp(cmd->pool, from, newmap->regflags);
+ newmap->to = to;
+ }
+ if (cond != NULL) {
+ /* back-compatibility: support old-style ENV expressions
+ * by converting to ap_expr syntax.
+ *
+ * 1. var --> env(var)
+ * 2. var=val --> env(var)=val
+ * 3. !var --> !env(var)
+ * 4. !var=val --> env(var)!=val
+ */
+ char *newcond = NULL;
+ if (ap_rxplus_exec(cmd->temp_pool, old_expr, cond, &newcond)) {
+ /* we got a substitution. Check for the case (3) above
+ * that the regexp gets wrong: a negation without a comparison.
+ */
+ if ((cond[0] == '!') && !ap_strchr_c(cond, '=')) {
+ memmove(newcond+1, newcond, strlen(newcond)-1);
+ newcond[0] = '!';
+ }
+ cond = newcond;
+ }
+ newmap->cond = ap_expr_parse_cmd(cmd, cond, 0, &err, NULL);
+ }
+ else {
+ newmap->cond = NULL;
+ }
+ return err;
+}
+static const char* set_urlmap(cmd_parms* cmd, void* CFG, const char* args)
+{
+ proxy_html_conf* cfg = (proxy_html_conf*)CFG;
+ urlmap* map;
+ apr_pool_t* pool = cmd->pool;
+ urlmap* newmap;
+ const char* usage =
+ "Usage: ProxyHTMLURLMap from-pattern to-pattern [flags] [cond]";
+ const char* from;
+ const char* to;
+ const char* flags;
+ const char* cond = NULL;
+
+ if (from = ap_getword_conf(cmd->pool, &args), !from)
+ return usage;
+ if (to = ap_getword_conf(cmd->pool, &args), !to)
+ return usage;
+ flags = ap_getword_conf(cmd->pool, &args);
+ if (flags && *flags)
+ cond = ap_getword_conf(cmd->pool, &args);
+ if (cond && !*cond)
+ cond = NULL;
+
+ /* the args look OK, so let's use them */
+ newmap = apr_palloc(pool, sizeof(urlmap));
+ newmap->next = NULL;
+ if (cfg->map) {
+ for (map = cfg->map; map->next; map = map->next);
+ map->next = newmap;
+ }
+ else
+ cfg->map = newmap;
+
+ return comp_urlmap(cmd, newmap, from, to, flags, cond);
+}
+
+static const char* set_doctype(cmd_parms* cmd, void* CFG,
+ const char* t, const char* l)
+{
+ proxy_html_conf* cfg = (proxy_html_conf*)CFG;
+ if (!strcasecmp(t, "xhtml")) {
+ cfg->etag = xhtml_etag;
+ if (l && !strcasecmp(l, "legacy"))
+ cfg->doctype = fpi_xhtml_legacy;
+ else
+ cfg->doctype = fpi_xhtml;
+ }
+ else if (!strcasecmp(t, "html")) {
+ cfg->etag = html_etag;
+ if (l && !strcasecmp(l, "legacy"))
+ cfg->doctype = fpi_html_legacy;
+ else
+ cfg->doctype = fpi_html;
+ }
+ else {
+ cfg->doctype = apr_pstrdup(cmd->pool, t);
+ if (l && ((l[0] == 'x') || (l[0] == 'X')))
+ cfg->etag = xhtml_etag;
+ else
+ cfg->etag = html_etag;
+ }
+ return NULL;
+}
+static const char* set_flags(cmd_parms* cmd, void* CFG, const char* arg)
+{
+ proxy_html_conf* cfg = CFG;
+ if (arg && *arg) {
+ if (!strcmp(arg, "lowercase"))
+ cfg->flags |= NORM_LC;
+ else if (!strcmp(arg, "dospath"))
+ cfg->flags |= NORM_MSSLASH;
+ else if (!strcmp(arg, "reset"))
+ cfg->flags |= NORM_RESET;
+ }
+ return NULL;
+}
+static const char* set_events(cmd_parms* cmd, void* CFG, const char* arg)
+{
+ tattr* attr;
+ proxy_html_conf* cfg = CFG;
+ if (cfg->events == NULL)
+ cfg->events = apr_array_make(cmd->pool, 20, sizeof(tattr));
+ attr = apr_array_push(cfg->events);
+ attr->val = arg;
+ return NULL;
+}
+static const char* set_links(cmd_parms* cmd, void* CFG,
+ const char* elt, const char* att)
+{
+ apr_array_header_t* attrs;
+ tattr* attr;
+ proxy_html_conf* cfg = CFG;
+
+ if (cfg->links == NULL)
+ cfg->links = apr_hash_make(cmd->pool);
+
+ attrs = apr_hash_get(cfg->links, elt, APR_HASH_KEY_STRING);
+ if (!attrs) {
+ attrs = apr_array_make(cmd->pool, 2, sizeof(tattr*));
+ apr_hash_set(cfg->links, elt, APR_HASH_KEY_STRING, attrs);
+ }
+ attr = apr_array_push(attrs);
+ attr->val = att;
+ return NULL;
+}
+static const command_rec proxy_html_cmds[] = {
+ AP_INIT_ITERATE("ProxyHTMLEvents", set_events, NULL,
+ RSRC_CONF|ACCESS_CONF,
+ "Strings to be treated as scripting events"),
+ AP_INIT_ITERATE2("ProxyHTMLLinks", set_links, NULL,
+ RSRC_CONF|ACCESS_CONF, "Declare HTML Attributes"),
+ AP_INIT_RAW_ARGS("ProxyHTMLURLMap", set_urlmap, NULL,
+ RSRC_CONF|ACCESS_CONF, "Map URL From To"),
+ AP_INIT_TAKE12("ProxyHTMLDoctype", set_doctype, NULL,
+ RSRC_CONF|ACCESS_CONF, "(HTML|XHTML) [Legacy]"),
+ AP_INIT_ITERATE("ProxyHTMLFixups", set_flags, NULL,
+ RSRC_CONF|ACCESS_CONF, "Options are lowercase, dospath"),
+ AP_INIT_FLAG("ProxyHTMLMeta", ap_set_flag_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, metafix),
+ RSRC_CONF|ACCESS_CONF, "Fix META http-equiv elements"),
+ AP_INIT_FLAG("ProxyHTMLInterp", ap_set_flag_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, interp),
+ RSRC_CONF|ACCESS_CONF,
+ "Support interpolation and conditions in URLMaps"),
+ AP_INIT_FLAG("ProxyHTMLExtended", ap_set_flag_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, extfix),
+ RSRC_CONF|ACCESS_CONF, "Map URLs in Javascript and CSS"),
+ AP_INIT_FLAG("ProxyHTMLStripComments", ap_set_flag_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, strip_comments),
+ RSRC_CONF|ACCESS_CONF, "Strip out comments"),
+ AP_INIT_TAKE1("ProxyHTMLBufSize", ap_set_int_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, bufsz),
+ RSRC_CONF|ACCESS_CONF, "Buffer size"),
+ AP_INIT_TAKE1("ProxyHTMLCharsetOut", ap_set_string_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, charset_out),
+ RSRC_CONF|ACCESS_CONF, "Usage: ProxyHTMLCharsetOut charset"),
+ AP_INIT_FLAG("ProxyHTMLEnable", ap_set_flag_slot,
+ (void*)APR_OFFSETOF(proxy_html_conf, enabled),
+ RSRC_CONF|ACCESS_CONF,
+ "Enable proxy-html and xml2enc filters"),
+ { NULL }
+};
+static int mod_proxy_html(apr_pool_t* p, apr_pool_t* p1, apr_pool_t* p2)
+{
+ seek_meta = ap_pregcomp(p, "<meta[^>]*(http-equiv)[^>]*>",
+ AP_REG_EXTENDED|AP_REG_ICASE);
+ seek_content = apr_strmatch_precompile(p, "content", 0);
+ memset(&sax, 0, sizeof(htmlSAXHandler));
+ sax.startElement = pstartElement;
+ sax.endElement = pendElement;
+ sax.characters = pcharacters;
+ sax.comment = pcomment;
+ sax.cdataBlock = pcdata;
+ xml2enc_charset = APR_RETRIEVE_OPTIONAL_FN(xml2enc_charset);
+ xml2enc_filter = APR_RETRIEVE_OPTIONAL_FN(xml2enc_filter);
+ if (!xml2enc_charset) {
+ ap_log_perror(APLOG_MARK, APLOG_NOTICE, 0, p2, APLOGNO(01425)
+ "I18n support in mod_proxy_html requires mod_xml2enc. "
+ "Without it, non-ASCII characters in proxied pages are "
+ "likely to display incorrectly.");
+ }
+
+ /* old_expr only needs to last the life of the config phase */
+ old_expr = ap_rxplus_compile(p1, "s/^(!)?(\\w+)((=)(.+))?$/reqenv('$2')$1$4'$5'/");
+ return OK;
+}
+static void proxy_html_insert(request_rec* r)
+{
+ proxy_html_conf* cfg;
+ cfg = ap_get_module_config(r->per_dir_config, &proxy_html_module);
+ if (cfg->enabled) {
+ if (xml2enc_filter)
+ xml2enc_filter(r, NULL, ENCIO_INPUT_CHECKS);
+ ap_add_output_filter("proxy-html", NULL, r, r->connection);
+ }
+}
+static void proxy_html_hooks(apr_pool_t* p)
+{
+ static const char* aszSucc[] = { "mod_filter.c", NULL };
+ ap_register_output_filter_protocol("proxy-html", proxy_html_filter,
+ NULL, AP_FTYPE_RESOURCE,
+ AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH);
+ /* move this to pre_config so old_expr is available to interpret
+ * old-style conditions on URL maps.
+ */
+ ap_hook_pre_config(mod_proxy_html, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_insert_filter(proxy_html_insert, NULL, aszSucc, APR_HOOK_MIDDLE);
+}
+module AP_MODULE_DECLARE_DATA proxy_html_module = {
+ STANDARD20_MODULE_STUFF,
+ proxy_html_config,
+ proxy_html_merge,
+ NULL,
+ NULL,
+ proxy_html_cmds,
+ proxy_html_hooks
+};
diff --git a/modules/filters/mod_proxy_html.dsp b/modules/filters/mod_proxy_html.dsp
new file mode 100644
index 00000000..149166cb
--- /dev/null
+++ b/modules/filters/mod_proxy_html.dsp
@@ -0,0 +1,123 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_html" - 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_proxy_html - Win32 Release
+!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_proxy_html.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_proxy_html.mak" CFG="mod_proxy_html - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_proxy_html - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_html - 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_proxy_html - 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 "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/libxml2/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_html_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG" /i "../../include" /i "../../srclib/apr/include" /I "../../srclib/apr-util/include" /i "../../srclib/libxml2/include"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_proxy_html.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_html.so
+# ADD LINK32 kernel32.lib libxml2.lib /nologo /subsystem:windows /dll /incremental:no /libpath:"../../srclib/libxml2/win32/bin.msvc" /debug /out:".\Release\mod_proxy_html.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_html.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_proxy_html.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_proxy_html - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/libxml2/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_html_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /i /d "_DEBUG" "../../include" /i "../../srclib/apr/include" /I "../../srclib/apr-util/include" /i "../../srclib/libxml2/include"
+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 /out:".\Debug\mod_proxy_html.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_html.so
+# ADD LINK32 kernel32.lib libxml2.lib /nologo /subsystem:windows /dll /incremental:no /libpath:"../../srclib/libxml2/win32/bin.msvc" /debug /out:".\Debug\mod_proxy_html.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_html.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_proxy_html.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_proxy_html - Win32 Release"
+# Name "mod_proxy_html - Win32 Debug"
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h"
+# Begin Source File
+
+SOURCE=.\mod_xml2enc.h
+# End Source File
+# End Group
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\mod_proxy_html.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/modules/filters/mod_ratelimit.c b/modules/filters/mod_ratelimit.c
new file mode 100644
index 00000000..028de361
--- /dev/null
+++ b/modules/filters/mod_ratelimit.c
@@ -0,0 +1,313 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "util_filter.h"
+
+#include "mod_ratelimit.h"
+
+#define RATE_LIMIT_FILTER_NAME "RATE_LIMIT"
+#define RATE_INTERVAL_MS (200)
+
+typedef enum rl_state_e
+{
+ RATE_ERROR,
+ RATE_LIMIT,
+ RATE_FULLSPEED
+} rl_state_e;
+
+typedef struct rl_ctx_t
+{
+ int speed;
+ int chunk_size;
+ rl_state_e state;
+ apr_bucket_brigade *tmpbb;
+ apr_bucket_brigade *holdingbb;
+} rl_ctx_t;
+
+#if 0
+static void brigade_dump(request_rec *r, apr_bucket_brigade *bb)
+{
+ apr_bucket *e;
+ int i = 0;
+
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e), i++) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "brigade: [%d] %s", i, e->type->name);
+
+ }
+}
+#endif
+
+static apr_status_t
+rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb)
+{
+ apr_status_t rv = APR_SUCCESS;
+ rl_ctx_t *ctx = f->ctx;
+ apr_bucket *fb;
+ int do_sleep = 0;
+ apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc;
+ apr_bucket_brigade *bb = input_bb;
+
+ if (f->c->aborted) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01454) "rl: conn aborted");
+ apr_brigade_cleanup(bb);
+ return APR_ECONNABORTED;
+ }
+
+ if (ctx == NULL) {
+
+ const char *rl = NULL;
+
+ /* no subrequests. */
+ if (f->r->main != NULL) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ rl = apr_table_get(f->r->subprocess_env, "rate-limit");
+
+ if (rl == NULL) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ /* first run, init stuff */
+ ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t));
+ f->ctx = ctx;
+ ctx->speed = 0;
+ ctx->state = RATE_LIMIT;
+
+ /* rl is in kilo bytes / second */
+ ctx->speed = atoi(rl) * 1024;
+
+ if (ctx->speed == 0) {
+ /* remove ourselves */
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ /* calculate how many bytes / interval we want to send */
+ /* speed is bytes / second, so, how many (speed / 1000 % interval) */
+ ctx->chunk_size = (ctx->speed / (1000 / RATE_INTERVAL_MS));
+ ctx->tmpbb = apr_brigade_create(f->r->pool, ba);
+ ctx->holdingbb = apr_brigade_create(f->r->pool, ba);
+ }
+
+ while (ctx->state != RATE_ERROR &&
+ (!APR_BRIGADE_EMPTY(bb) || !APR_BRIGADE_EMPTY(ctx->holdingbb))) {
+ apr_bucket *e;
+
+ if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) {
+ APR_BRIGADE_CONCAT(bb, ctx->holdingbb);
+ apr_brigade_cleanup(ctx->holdingbb);
+ }
+
+ while (ctx->state == RATE_FULLSPEED && !APR_BRIGADE_EMPTY(bb)) {
+ /* Find where we 'stop' going full speed. */
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
+ if (AP_RL_BUCKET_IS_END(e)) {
+ apr_bucket *f;
+ f = APR_RING_LAST(&bb->list);
+ APR_RING_UNSPLICE(e, f, link);
+ APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f,
+ apr_bucket, link);
+ ctx->state = RATE_LIMIT;
+ break;
+ }
+ }
+
+ if (f->c->aborted) {
+ apr_brigade_cleanup(bb);
+ ctx->state = RATE_ERROR;
+ break;
+ }
+
+ fb = apr_bucket_flush_create(ba);
+ APR_BRIGADE_INSERT_TAIL(bb, fb);
+ rv = ap_pass_brigade(f->next, bb);
+
+ if (rv != APR_SUCCESS) {
+ ctx->state = RATE_ERROR;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01455)
+ "rl: full speed brigade pass failed.");
+ }
+ }
+
+ while (ctx->state == RATE_LIMIT && !APR_BRIGADE_EMPTY(bb)) {
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) {
+ if (AP_RL_BUCKET_IS_START(e)) {
+ apr_bucket *f;
+ f = APR_RING_LAST(&bb->list);
+ APR_RING_UNSPLICE(e, f, link);
+ APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f,
+ apr_bucket, link);
+ ctx->state = RATE_FULLSPEED;
+ break;
+ }
+ }
+
+ while (!APR_BRIGADE_EMPTY(bb)) {
+ apr_bucket *stop_point;
+ apr_off_t len = 0;
+
+ if (f->c->aborted) {
+ apr_brigade_cleanup(bb);
+ ctx->state = RATE_ERROR;
+ break;
+ }
+
+ if (do_sleep) {
+ apr_sleep(RATE_INTERVAL_MS * 1000);
+ }
+ else {
+ do_sleep = 1;
+ }
+
+ apr_brigade_length(bb, 1, &len);
+
+ rv = apr_brigade_partition(bb, ctx->chunk_size, &stop_point);
+ if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
+ ctx->state = RATE_ERROR;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01456)
+ "rl: partition failed.");
+ break;
+ }
+
+ if (stop_point != APR_BRIGADE_SENTINEL(bb)) {
+ apr_bucket *f;
+ apr_bucket *e = APR_BUCKET_PREV(stop_point);
+ f = APR_RING_FIRST(&bb->list);
+ APR_RING_UNSPLICE(f, e, link);
+ APR_RING_SPLICE_HEAD(&ctx->tmpbb->list, f, e, apr_bucket,
+ link);
+ }
+ else {
+ APR_BRIGADE_CONCAT(ctx->tmpbb, bb);
+ }
+
+ fb = apr_bucket_flush_create(ba);
+
+ APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb);
+
+#if 0
+ brigade_dump(f->r, ctx->tmpbb);
+ brigade_dump(f->r, bb);
+#endif
+
+ rv = ap_pass_brigade(f->next, ctx->tmpbb);
+ apr_brigade_cleanup(ctx->tmpbb);
+
+ if (rv != APR_SUCCESS) {
+ ctx->state = RATE_ERROR;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01457)
+ "rl: brigade pass failed.");
+ break;
+ }
+ }
+ }
+ }
+
+ return rv;
+}
+
+
+static apr_status_t
+rl_bucket_read(apr_bucket *b, const char **str,
+ apr_size_t *len, apr_read_type_e block)
+{
+ *str = NULL;
+ *len = 0;
+ return APR_SUCCESS;
+}
+
+AP_RL_DECLARE(apr_bucket *)
+ ap_rl_end_create(apr_bucket_alloc_t *list)
+{
+ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+ APR_BUCKET_INIT(b);
+ b->free = apr_bucket_free;
+ b->list = list;
+ b->length = 0;
+ b->start = 0;
+ b->data = NULL;
+ b->type = &ap_rl_bucket_type_end;
+
+ return b;
+}
+
+AP_RL_DECLARE(apr_bucket *)
+ ap_rl_start_create(apr_bucket_alloc_t *list)
+{
+ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+ APR_BUCKET_INIT(b);
+ b->free = apr_bucket_free;
+ b->list = list;
+ b->length = 0;
+ b->start = 0;
+ b->data = NULL;
+ b->type = &ap_rl_bucket_type_start;
+
+ return b;
+}
+
+
+
+AP_RL_DECLARE_DATA const apr_bucket_type_t ap_rl_bucket_type_end = {
+ "RL_END", 5, APR_BUCKET_METADATA,
+ apr_bucket_destroy_noop,
+ rl_bucket_read,
+ apr_bucket_setaside_noop,
+ apr_bucket_split_notimpl,
+ apr_bucket_simple_copy
+};
+
+
+AP_RL_DECLARE_DATA const apr_bucket_type_t ap_rl_bucket_type_start = {
+ "RL_START", 5, APR_BUCKET_METADATA,
+ apr_bucket_destroy_noop,
+ rl_bucket_read,
+ apr_bucket_setaside_noop,
+ apr_bucket_split_notimpl,
+ apr_bucket_simple_copy
+};
+
+
+
+
+static void register_hooks(apr_pool_t *p)
+{
+ /* run after mod_deflate etc etc, but not at connection level, ie, mod_ssl. */
+ ap_register_output_filter(RATE_LIMIT_FILTER_NAME, rate_limit_filter,
+ NULL, AP_FTYPE_PROTOCOL + 3);
+}
+
+AP_DECLARE_MODULE(ratelimit) = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ NULL, /* command apr_table_t */
+ register_hooks
+};
diff --git a/modules/filters/mod_ratelimit.dsp b/modules/filters/mod_ratelimit.dsp
new file mode 100644
index 00000000..99bb5950
--- /dev/null
+++ b/modules/filters/mod_ratelimit.dsp
@@ -0,0 +1,115 @@
+# Microsoft Developer Studio Project File - Name="mod_ratelimit" - 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_ratelimit - Win32 Release
+!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_ratelimit.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_ratelimit.mak" CFG="mod_ratelimit - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_ratelimit - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_ratelimit - 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_ratelimit - 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 "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_RL_DECLARE_EXPORT" /Fd"Release\mod_ratelimit_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_ratelimit.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_ratelimit.so" /d LONG_NAME="ratelimit_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_ratelimit.so" /base:@..\..\os\win32\BaseAddr.ref,mod_ratelimit.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_ratelimit.so" /base:@..\..\os\win32\BaseAddr.ref,mod_ratelimit.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_ratelimit.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_ratelimit - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_RL_DECLARE_EXPORT" /Fd"Debug\mod_ratelimit_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_ratelimit.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_ratelimit.so" /d LONG_NAME="ratelimit_module for Apache"
+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 /out:".\Debug\mod_ratelimit.so" /base:@..\..\os\win32\BaseAddr.ref,mod_ratelimit.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_ratelimit.so" /base:@..\..\os\win32\BaseAddr.ref,mod_ratelimit.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_ratelimit.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_ratelimit - Win32 Release"
+# Name "mod_ratelimit - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_ratelimit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_ratelimit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/filters/mod_ratelimit.h b/modules/filters/mod_ratelimit.h
new file mode 100644
index 00000000..6c69bb1a
--- /dev/null
+++ b/modules/filters/mod_ratelimit.h
@@ -0,0 +1,51 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#ifndef _MOD_RATELIMIT_H_
+#define _MOD_RATELIMIT_H_
+
+/* Create a set of AP_RL_DECLARE(type), AP_RL_DECLARE_NONSTD(type) and
+ * AP_RL_DECLARE_DATA with appropriate export and import tags for the platform
+ */
+#if !defined(WIN32)
+#define AP_RL_DECLARE(type) type
+#define AP_RL_DECLARE_NONSTD(type) type
+#define AP_RL_DECLARE_DATA
+#elif defined(AP_RL_DECLARE_STATIC)
+#define AP_RL_DECLARE(type) type __stdcall
+#define AP_RL_DECLARE_NONSTD(type) type
+#define AP_RL_DECLARE_DATA
+#elif defined(AP_RL_DECLARE_EXPORT)
+#define AP_RL_DECLARE(type) __declspec(dllexport) type __stdcall
+#define AP_RL_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define AP_RL_DECLARE_DATA __declspec(dllexport)
+#else
+#define AP_RL_DECLARE(type) __declspec(dllimport) type __stdcall
+#define AP_RL_DECLARE_NONSTD(type) __declspec(dllimport) type
+#define AP_RL_DECLARE_DATA __declspec(dllimport)
+#endif
+
+AP_RL_DECLARE_DATA extern const apr_bucket_type_t ap_rl_bucket_type_end;
+AP_RL_DECLARE_DATA extern const apr_bucket_type_t ap_rl_bucket_type_start;
+
+#define AP_RL_BUCKET_IS_END(e) (e->type == &ap_rl_bucket_type_end)
+#define AP_RL_BUCKET_IS_START(e) (e->type == &ap_rl_bucket_type_start)
+
+/* TODO: Make these Optional Functions, so that module load order doesn't matter. */
+AP_RL_DECLARE(apr_bucket*) ap_rl_end_create(apr_bucket_alloc_t *list);
+AP_RL_DECLARE(apr_bucket*) ap_rl_start_create(apr_bucket_alloc_t *list);
+
+#endif
diff --git a/modules/filters/mod_reflector.c b/modules/filters/mod_reflector.c
new file mode 100644
index 00000000..469df8e8
--- /dev/null
+++ b/modules/filters/mod_reflector.c
@@ -0,0 +1,232 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+#include "apr_strings.h"
+#include "apr_tables.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 "mod_core.h"
+
+module AP_MODULE_DECLARE_DATA reflector_module;
+
+typedef struct {
+ apr_table_t *headers;
+} reflector_cfg;
+
+static int header_do(void *dummy, const char *key, const char *value)
+{
+ request_rec *r = (request_rec *) dummy;
+ const char *payload;
+
+ payload = apr_table_get(r->headers_in, key);
+ if (payload) {
+ apr_table_setn(r->headers_out, value, payload);
+ }
+
+ return 1;
+}
+
+static int reflector_handler(request_rec * r)
+{
+ apr_bucket_brigade *bbin, *bbout;
+ reflector_cfg *conf;
+ apr_status_t status;
+
+ if (strcmp(r->handler, "reflector")) {
+ return DECLINED;
+ }
+
+ conf = (reflector_cfg *) ap_get_module_config(r->per_dir_config,
+ &reflector_module);
+
+ ap_allow_methods(r, 1, "POST", "OPTIONS", NULL);
+
+ if (r->method_number == M_OPTIONS) {
+ return ap_send_http_options(r);
+ }
+
+ else if (r->method_number == M_POST) {
+ const char *content_length, *content_type;
+ int seen_eos;
+
+ /*
+ * Sometimes we'll get in a state where the input handling has
+ * detected an error where we want to drop the connection, so if
+ * that's the case, don't read the data as that is what we're trying
+ * to avoid.
+ *
+ * This function is also a no-op on a subrequest.
+ */
+ if (r->main || r->connection->keepalive == AP_CONN_CLOSE ||
+ ap_status_drops_connection(r->status)) {
+ return OK;
+ }
+
+ /* copy headers from in to out if configured */
+ apr_table_do(header_do, r, conf->headers, NULL);
+
+ /* last modified defaults to now, unless otherwise set on the way in */
+ if (!apr_table_get(r->headers_out, "Last-Modified")) {
+ ap_update_mtime(r, apr_time_now());
+ ap_set_last_modified(r);
+ }
+ ap_set_accept_ranges(r);
+
+ /* reflect the content length, if present */
+ if ((content_length = apr_table_get(r->headers_in, "Content-Length"))) {
+ apr_off_t offset;
+
+ apr_strtoff(&offset, content_length, NULL, 10);
+ ap_set_content_length(r, offset);
+
+ }
+
+ /* reflect the content type, if present */
+ if ((content_type = apr_table_get(r->headers_in, "Content-Type"))) {
+
+ ap_set_content_type(r, content_type);
+
+ }
+
+ bbin = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ bbout = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+
+ seen_eos = 0;
+ do {
+ apr_bucket *bucket;
+
+ status = ap_get_brigade(r->input_filters, bbin, AP_MODE_READBYTES,
+ APR_BLOCK_READ, HUGE_STRING_LEN);
+
+ if (status != APR_SUCCESS) {
+ if (status == AP_FILTER_ERROR) {
+ apr_brigade_destroy(bbin);
+ return status;
+ }
+ else {
+ apr_brigade_destroy(bbin);
+ return HTTP_BAD_REQUEST;
+ }
+ }
+
+ for (bucket = APR_BRIGADE_FIRST(bbin);
+ bucket != APR_BRIGADE_SENTINEL(bbin);
+ bucket = APR_BUCKET_NEXT(bucket)) {
+ const char *data;
+ apr_size_t len;
+
+ if (APR_BUCKET_IS_EOS(bucket)) {
+ seen_eos = 1;
+ break;
+ }
+
+ /* These are metadata buckets. */
+ if (bucket->length == 0) {
+ continue;
+ }
+
+ /*
+ * We MUST read because in case we have an unknown-length
+ * bucket or one that morphs, we want to exhaust it.
+ */
+ status = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
+ if (status != APR_SUCCESS) {
+ apr_brigade_destroy(bbin);
+ return HTTP_BAD_REQUEST;
+ }
+
+ apr_brigade_write(bbout, NULL, NULL, data, len);
+
+ status = ap_pass_brigade(r->output_filters, bbout);
+ if (status != APR_SUCCESS) {
+ /* no way to know what type of error occurred */
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(01410)
+ "reflector_handler: ap_pass_brigade returned %i",
+ status);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ }
+
+ apr_brigade_cleanup(bbin);
+
+ } while (!seen_eos);
+
+ return OK;
+
+ }
+
+ else {
+ return HTTP_METHOD_NOT_ALLOWED;
+ }
+
+}
+
+static void *create_reflector_dir_config(apr_pool_t * p, char *d)
+{
+ reflector_cfg *conf = apr_pcalloc(p, sizeof(reflector_cfg));
+
+ conf->headers = apr_table_make(p, 8);
+
+ return conf;
+}
+
+static void *merge_reflector_dir_config(apr_pool_t * p, void *basev, void *addv)
+{
+ reflector_cfg *new = (reflector_cfg *) apr_pcalloc(p,
+ sizeof(reflector_cfg));
+ reflector_cfg *add = (reflector_cfg *) addv;
+ reflector_cfg *base = (reflector_cfg *) basev;
+
+ new->headers = apr_table_overlay(p, add->headers, base->headers);
+
+ return new;
+}
+
+static const char *reflector_header(cmd_parms * cmd, void *dummy, const char *in,
+ const char *out)
+{
+ reflector_cfg *cfg = (reflector_cfg *) dummy;
+
+ apr_table_addn(cfg->headers, in, out ? out : in);
+
+ return NULL;
+}
+
+static void reflector_hooks(apr_pool_t * p)
+{
+ ap_hook_handler(reflector_handler, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+static const command_rec reflector_cmds[] = {
+ AP_INIT_TAKE12("ReflectorHeader", reflector_header, NULL, OR_OPTIONS,
+ "Header to reflect back in the response, with an optional new name."),
+ {NULL}
+};
+
+AP_DECLARE_MODULE(reflector) = {
+ STANDARD20_MODULE_STUFF,
+ create_reflector_dir_config,
+ merge_reflector_dir_config,
+ NULL,
+ NULL,
+ reflector_cmds,
+ reflector_hooks
+};
diff --git a/modules/filters/mod_reflector.dsp b/modules/filters/mod_reflector.dsp
new file mode 100644
index 00000000..789d07f4
--- /dev/null
+++ b/modules/filters/mod_reflector.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_reflector" - 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_reflector - Win32 Release
+!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_reflector.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_reflector.mak" CFG="mod_reflector - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_reflector - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_reflector - 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_reflector - 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 "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_RL_DECLARE_EXPORT" /Fd"Release\mod_reflector_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_reflector.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_reflector.so" /d LONG_NAME="ratelimit_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_reflector.so" /base:@..\..\os\win32\BaseAddr.ref,mod_reflector.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_reflector.so" /base:@..\..\os\win32\BaseAddr.ref,mod_reflector.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_reflector.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_reflector - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_RL_DECLARE_EXPORT" /Fd"Debug\mod_reflector_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_reflector.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_reflector.so" /d LONG_NAME="ratelimit_module for Apache"
+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 /out:".\Debug\mod_reflector.so" /base:@..\..\os\win32\BaseAddr.ref,mod_reflector.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_reflector.so" /base:@..\..\os\win32\BaseAddr.ref,mod_reflector.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_reflector.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_reflector - Win32 Release"
+# Name "mod_reflector - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_reflector.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/filters/mod_reqtimeout.c b/modules/filters/mod_reqtimeout.c
index bc04e684..e71a3251 100644
--- a/modules/filters/mod_reqtimeout.c
+++ b/modules/filters/mod_reqtimeout.c
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#define CORE_PRIVATE
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
@@ -29,6 +28,14 @@
module AP_MODULE_DECLARE_DATA reqtimeout_module;
+#define UNSET -1
+#define MRT_DEFAULT_HEADER_TIMEOUT 20
+#define MRT_DEFAULT_HEADER_MAX_TIMEOUT 40
+#define MRT_DEFAULT_HEADER_MIN_RATE 500
+#define MRT_DEFAULT_BODY_TIMEOUT 20
+#define MRT_DEFAULT_BODY_MAX_TIMEOUT 0
+#define MRT_DEFAULT_BODY_MIN_RATE 500
+
typedef struct
{
int header_timeout; /* timeout for reading the req hdrs in secs */
@@ -57,6 +64,8 @@ typedef struct
} reqtimeout_con_cfg;
static const char *const reqtimeout_filter_name = "reqtimeout";
+static int default_header_rate_factor;
+static int default_body_rate_factor;
static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
{
@@ -76,12 +85,15 @@ static void extend_timeout(reqtimeout_con_cfg *ccfg, apr_bucket_brigade *bb)
}
static apr_status_t check_time_left(reqtimeout_con_cfg *ccfg,
- apr_time_t *time_left_p)
+ apr_time_t *time_left_p,
+ apr_time_t now)
{
- *time_left_p = ccfg->timeout_at - apr_time_now();
+ if (!now)
+ now = apr_time_now();
+ *time_left_p = ccfg->timeout_at - now;
if (*time_left_p <= 0)
return APR_TIMEUP;
-
+
if (*time_left_p < apr_time_from_sec(1)) {
*time_left_p = apr_time_from_sec(1);
}
@@ -93,9 +105,9 @@ static apr_status_t have_lf_or_eos(apr_bucket_brigade *bb)
apr_bucket *b = APR_BRIGADE_LAST(bb);
for ( ; b != APR_BRIGADE_SENTINEL(bb) ; b = APR_BUCKET_PREV(b) ) {
- const char *str;
- apr_size_t len;
- apr_status_t rv;
+ const char *str;
+ apr_size_t len;
+ apr_status_t rv;
if (APR_BUCKET_IS_EOS(b))
return APR_SUCCESS;
@@ -160,9 +172,9 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
apr_off_t readbytes)
{
apr_time_t time_left;
- apr_time_t now;
+ apr_time_t now = 0;
apr_status_t rv;
- apr_interval_time_t saved_sock_timeout = -1;
+ apr_interval_time_t saved_sock_timeout = UNSET;
reqtimeout_con_cfg *ccfg = f->ctx;
if (ccfg->in_keep_alive) {
@@ -171,9 +183,9 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
return ap_get_brigade(f->next, bb, mode, block, readbytes);
}
- now = apr_time_now();
if (ccfg->new_timeout > 0) {
/* set new timeout */
+ now = apr_time_now();
ccfg->timeout_at = now + apr_time_from_sec(ccfg->new_timeout);
ccfg->new_timeout = 0;
if (ccfg->new_max_timeout > 0) {
@@ -187,10 +199,10 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
}
if (!ccfg->socket) {
- ccfg->socket = ap_get_module_config(f->c->conn_config, &core_module);
+ ccfg->socket = ap_get_conn_socket(f->c);
}
- rv = check_time_left(ccfg, &time_left);
+ rv = check_time_left(ccfg, &time_left, now);
if (rv != APR_SUCCESS)
goto out;
@@ -272,7 +284,7 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
if (rv != APR_SUCCESS)
break;
- rv = check_time_left(ccfg, &time_left);
+ rv = check_time_left(ccfg, &time_left, 0);
if (rv != APR_SUCCESS)
break;
@@ -298,7 +310,7 @@ static apr_status_t reqtimeout_filter(ap_filter_t *f,
out:
if (APR_STATUS_IS_TIMEUP(rv)) {
- ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c, APLOGNO(01382)
"Request %s read timeout", ccfg->type);
/*
* If we allow a normal lingering close, the client may keep this
@@ -326,17 +338,25 @@ static int reqtimeout_init(conn_rec *c)
cfg = ap_get_module_config(c->base_server->module_config,
&reqtimeout_module);
AP_DEBUG_ASSERT(cfg != NULL);
- if (cfg->header_timeout <= 0 && cfg->body_timeout <= 0) {
- /* not configured for this vhost */
+ if (cfg->header_timeout == 0 && cfg->body_timeout == 0) {
+ /* disabled for this vhost */
return DECLINED;
}
ccfg = apr_pcalloc(c->pool, sizeof(reqtimeout_con_cfg));
- ccfg->new_timeout = cfg->header_timeout;
- ccfg->new_max_timeout = cfg->header_max_timeout;
ccfg->type = "header";
- ccfg->min_rate = cfg->header_min_rate;
- ccfg->rate_factor = cfg->header_rate_factor;
+ if (cfg->header_timeout != UNSET) {
+ ccfg->new_timeout = cfg->header_timeout;
+ ccfg->new_max_timeout = cfg->header_max_timeout;
+ ccfg->min_rate = cfg->header_min_rate;
+ ccfg->rate_factor = cfg->header_rate_factor;
+ }
+ else {
+ ccfg->new_timeout = MRT_DEFAULT_HEADER_TIMEOUT;
+ ccfg->new_max_timeout = MRT_DEFAULT_HEADER_MAX_TIMEOUT;
+ ccfg->min_rate = MRT_DEFAULT_HEADER_MIN_RATE;
+ ccfg->rate_factor = default_header_rate_factor;
+ }
ap_set_module_config(c->conn_config, &reqtimeout_module, ccfg);
ap_add_input_filter("reqtimeout", ccfg, NULL, c);
@@ -350,25 +370,29 @@ static int reqtimeout_after_headers(request_rec *r)
reqtimeout_con_cfg *ccfg =
ap_get_module_config(r->connection->conn_config, &reqtimeout_module);
- if (ccfg == NULL) {
- /* not configured for this connection */
+ if (ccfg == NULL || r->method_number == M_CONNECT) {
+ /* either disabled for this connection or a CONNECT request */
return OK;
}
-
cfg = ap_get_module_config(r->connection->base_server->module_config,
&reqtimeout_module);
AP_DEBUG_ASSERT(cfg != NULL);
ccfg->timeout_at = 0;
ccfg->max_timeout_at = 0;
- if (r->method_number != M_CONNECT) {
- ccfg->new_timeout = cfg->body_timeout;
+ ccfg->type = "body";
+ if (cfg->body_timeout != UNSET) {
+ ccfg->new_timeout = cfg->body_timeout;
ccfg->new_max_timeout = cfg->body_max_timeout;
- ccfg->min_rate = cfg->body_min_rate;
- ccfg->rate_factor = cfg->body_rate_factor;
- ccfg->type = "body";
+ ccfg->min_rate = cfg->body_min_rate;
+ ccfg->rate_factor = cfg->body_rate_factor;
+ }
+ else {
+ ccfg->new_timeout = MRT_DEFAULT_BODY_TIMEOUT;
+ ccfg->new_max_timeout = MRT_DEFAULT_BODY_MAX_TIMEOUT;
+ ccfg->min_rate = MRT_DEFAULT_BODY_MIN_RATE;
+ ccfg->rate_factor = default_body_rate_factor;
}
-
return OK;
}
@@ -390,12 +414,19 @@ static int reqtimeout_after_body(request_rec *r)
ccfg->timeout_at = 0;
ccfg->max_timeout_at = 0;
ccfg->in_keep_alive = 1;
- ccfg->new_timeout = cfg->header_timeout;
- ccfg->new_max_timeout = cfg->header_max_timeout;
- ccfg->min_rate = cfg->header_min_rate;
- ccfg->rate_factor = cfg->header_rate_factor;
-
ccfg->type = "header";
+ if (ccfg->new_timeout != UNSET) {
+ ccfg->new_timeout = cfg->header_timeout;
+ ccfg->new_max_timeout = cfg->header_max_timeout;
+ ccfg->min_rate = cfg->header_min_rate;
+ ccfg->rate_factor = cfg->header_rate_factor;
+ }
+ else {
+ ccfg->new_timeout = MRT_DEFAULT_HEADER_TIMEOUT;
+ ccfg->new_max_timeout = MRT_DEFAULT_HEADER_MAX_TIMEOUT;
+ ccfg->min_rate = MRT_DEFAULT_HEADER_MIN_RATE;
+ ccfg->rate_factor = default_header_rate_factor;
+ }
return OK;
}
@@ -404,17 +435,17 @@ static void *reqtimeout_create_srv_config(apr_pool_t *p, server_rec *s)
{
reqtimeout_srv_cfg *cfg = apr_pcalloc(p, sizeof(reqtimeout_srv_cfg));
- cfg->header_timeout = -1;
- cfg->header_max_timeout = -1;
- cfg->header_min_rate = -1;
- cfg->body_timeout = -1;
- cfg->body_max_timeout = -1;
- cfg->body_min_rate = -1;
+ cfg->header_timeout = UNSET;
+ cfg->header_max_timeout = UNSET;
+ cfg->header_min_rate = UNSET;
+ cfg->body_timeout = UNSET;
+ cfg->body_max_timeout = UNSET;
+ cfg->body_min_rate = UNSET;
return cfg;
}
-#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == -1) ? b->val : a->val;
+#define MERGE_INT(cfg, b, a, val) cfg->val = (a->val == UNSET) ? b->val : a->val;
static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
{
reqtimeout_srv_cfg *base = base_;
@@ -428,11 +459,10 @@ static void *reqtimeout_merge_srv_config(apr_pool_t *p, void *base_, void *add_)
MERGE_INT(cfg, base, add, body_max_timeout);
MERGE_INT(cfg, base, add, body_min_rate);
- cfg->header_rate_factor = (cfg->header_min_rate == -1) ? base->header_rate_factor :
- add->header_rate_factor;
- cfg->body_rate_factor = (cfg->body_min_rate == -1) ? base->body_rate_factor :
- add->body_rate_factor;
-
+ cfg->header_rate_factor = (cfg->header_min_rate == UNSET) ?
+ base->header_rate_factor : add->header_rate_factor;
+ cfg->body_rate_factor = (cfg->body_min_rate == UNSET) ?
+ base->body_rate_factor : add->body_rate_factor;
return cfg;
}
@@ -471,7 +501,7 @@ static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
else {
return "Unknown RequestReadTimeout parameter";
}
-
+
if ((rate_str = ap_strcasestr(val, ",minrate="))) {
initial_str = apr_pstrndup(p, val, rate_str - val);
rate_str += strlen(",minrate=");
@@ -488,7 +518,7 @@ static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
if (ret)
return ret;
}
-
+
ret = parse_int(p, initial_str, &initial);
}
else {
@@ -496,7 +526,7 @@ static const char *set_reqtimeout_param(reqtimeout_srv_cfg *conf,
return "Must set MinRate option if using timeout range";
ret = parse_int(p, val, &initial);
}
-
+
if (ret)
return ret;
@@ -527,12 +557,12 @@ static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
reqtimeout_srv_cfg *conf =
ap_get_module_config(cmd->server->module_config,
&reqtimeout_module);
-
+
while (*arg) {
char *word, *val;
const char *err;
-
- word = ap_getword_conf(cmd->pool, &arg);
+
+ word = ap_getword_conf(cmd->temp_pool, &arg);
val = strchr(word, '=');
if (!val) {
return "Invalid RequestReadTimeout parameter. Parameter must be "
@@ -542,14 +572,14 @@ static const char *set_reqtimeouts(cmd_parms *cmd, void *mconfig,
*val++ = '\0';
err = set_reqtimeout_param(conf, cmd->pool, word, val);
-
+
if (err)
return apr_psprintf(cmd->temp_pool, "RequestReadTimeout: %s=%s: %s",
word, val, err);
}
-
+
return NULL;
-
+
}
static void reqtimeout_hooks(apr_pool_t *pool)
@@ -575,6 +605,13 @@ static void reqtimeout_hooks(apr_pool_t *pool)
APR_HOOK_MIDDLE);
ap_hook_log_transaction(reqtimeout_after_body, NULL, NULL,
APR_HOOK_MIDDLE);
+
+#if MRT_DEFAULT_HEADER_MIN_RATE > 0
+ default_header_rate_factor = apr_time_from_sec(1) / MRT_DEFAULT_HEADER_MIN_RATE;
+#endif
+#if MRT_DEFAULT_BODY_MIN_RATE > 0
+ default_body_rate_factor = apr_time_from_sec(1) / MRT_DEFAULT_BODY_MIN_RATE;
+#endif
}
static const command_rec reqtimeout_cmds[] = {
@@ -584,7 +621,7 @@ static const command_rec reqtimeout_cmds[] = {
{NULL}
};
-module AP_MODULE_DECLARE_DATA reqtimeout_module = {
+AP_DECLARE_MODULE(reqtimeout) = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
diff --git a/modules/filters/mod_reqtimeout.dep b/modules/filters/mod_reqtimeout.dep
deleted file mode 100644
index 7a96e657..00000000
--- a/modules/filters/mod_reqtimeout.dep
+++ /dev/null
@@ -1,32 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_reqtimeout.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_reqtimeout.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.h"\
- "..\..\include\http_config.h"\
- "..\..\include\http_connection.h"\
- "..\..\include\http_core.h"\
- "..\..\include\http_log.h"\
- "..\..\include\http_protocol.h"\
- "..\..\include\http_request.h"\
- "..\..\include\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_filter.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_hash.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_portable.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
- "..\..\srclib\apr\include\apr_version.h"\
-
diff --git a/modules/filters/mod_reqtimeout.mak b/modules/filters/mod_reqtimeout.mak
deleted file mode 100644
index 3839f834..00000000
--- a/modules/filters/mod_reqtimeout.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_reqtimeout.dsp
-!IF "$(CFG)" == ""
-CFG=mod_reqtimeout - Win32 Release
-!MESSAGE No configuration specified. Defaulting to mod_reqtimeout - Win32 Release.
-!ENDIF
-
-!IF "$(CFG)" != "mod_reqtimeout - Win32 Release" && "$(CFG)" != "mod_reqtimeout - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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_reqtimeout.mak" CFG="mod_reqtimeout - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_reqtimeout - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_reqtimeout - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_reqtimeout - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_reqtimeout.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_reqtimeout.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_reqtimeout.obj"
- -@erase "$(INTDIR)\mod_reqtimeout.res"
- -@erase "$(INTDIR)\mod_reqtimeout_src.idb"
- -@erase "$(INTDIR)\mod_reqtimeout_src.pdb"
- -@erase "$(OUTDIR)\mod_reqtimeout.exp"
- -@erase "$(OUTDIR)\mod_reqtimeout.lib"
- -@erase "$(OUTDIR)\mod_reqtimeout.pdb"
- -@erase "$(OUTDIR)\mod_reqtimeout.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_RL_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_reqtimeout_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_reqtimeout.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_reqtimeout.so" /d LONG_NAME="reqtimeout_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_reqtimeout.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_reqtimeout.pdb" /debug /out:"$(OUTDIR)\mod_reqtimeout.so" /implib:"$(OUTDIR)\mod_reqtimeout.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_reqtimeout.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_reqtimeout.obj" \
- "$(INTDIR)\mod_reqtimeout.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_reqtimeout.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_reqtimeout.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_reqtimeout.so"
- if exist .\Release\mod_reqtimeout.so.manifest mt.exe -manifest .\Release\mod_reqtimeout.so.manifest -outputresource:.\Release\mod_reqtimeout.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_reqtimeout - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_reqtimeout.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_reqtimeout.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_reqtimeout.obj"
- -@erase "$(INTDIR)\mod_reqtimeout.res"
- -@erase "$(INTDIR)\mod_reqtimeout_src.idb"
- -@erase "$(INTDIR)\mod_reqtimeout_src.pdb"
- -@erase "$(OUTDIR)\mod_reqtimeout.exp"
- -@erase "$(OUTDIR)\mod_reqtimeout.lib"
- -@erase "$(OUTDIR)\mod_reqtimeout.pdb"
- -@erase "$(OUTDIR)\mod_reqtimeout.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_RL_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_reqtimeout_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_reqtimeout.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_reqtimeout.so" /d LONG_NAME="reqtimeout_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_reqtimeout.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_reqtimeout.pdb" /debug /out:"$(OUTDIR)\mod_reqtimeout.so" /implib:"$(OUTDIR)\mod_reqtimeout.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_reqtimeout.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_reqtimeout.obj" \
- "$(INTDIR)\mod_reqtimeout.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_reqtimeout.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_reqtimeout.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_reqtimeout.so"
- if exist .\Debug\mod_reqtimeout.so.manifest mt.exe -manifest .\Debug\mod_reqtimeout.so.manifest -outputresource:.\Debug\mod_reqtimeout.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_reqtimeout.dep")
-!INCLUDE "mod_reqtimeout.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_reqtimeout.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_reqtimeout - Win32 Release" || "$(CFG)" == "mod_reqtimeout - Win32 Debug"
-
-!IF "$(CFG)" == "mod_reqtimeout - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_reqtimeout - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_reqtimeout - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_reqtimeout - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_reqtimeout - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_reqtimeout - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_reqtimeout - Win32 Release"
-
-
-"$(INTDIR)\mod_reqtimeout.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_reqtimeout.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_reqtimeout.so" /d LONG_NAME="reqtimeout_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_reqtimeout - Win32 Debug"
-
-
-"$(INTDIR)\mod_reqtimeout.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_reqtimeout.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_reqtimeout.so" /d LONG_NAME="reqtimeout_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_reqtimeout.c
-
-"$(INTDIR)\mod_reqtimeout.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_request.c b/modules/filters/mod_request.c
new file mode 100644
index 00000000..ae59ab63
--- /dev/null
+++ b/modules/filters/mod_request.c
@@ -0,0 +1,396 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+ * mod_request.c --- HTTP routines to set aside or process request bodies.
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_lib.h"
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_protocol.h"
+#include "http_log.h" /* For errors detected in basic auth common
+ * support code... */
+#include "http_request.h"
+
+#include "mod_request.h"
+
+/* Handles for core filters */
+static ap_filter_rec_t *keep_body_input_filter_handle;
+static ap_filter_rec_t *kept_body_input_filter_handle;
+
+static apr_status_t bail_out_on_error(apr_bucket_brigade *bb,
+ ap_filter_t *f,
+ int http_error)
+{
+ apr_bucket *e;
+
+ apr_brigade_cleanup(bb);
+ e = ap_bucket_error_create(http_error,
+ NULL, f->r->pool,
+ f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ e = apr_bucket_eos_create(f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ return ap_pass_brigade(f->r->output_filters, bb);
+}
+
+typedef struct keep_body_filter_ctx {
+ apr_off_t remaining;
+ apr_off_t keep_body;
+} keep_body_ctx_t;
+
+/**
+ * This is the KEEP_BODY_INPUT filter for HTTP requests, for times when the
+ * body should be set aside for future use by other modules.
+ */
+static apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t readbytes)
+{
+ apr_bucket *e;
+ keep_body_ctx_t *ctx = f->ctx;
+ apr_status_t rv;
+ apr_bucket *bucket;
+ apr_off_t len = 0;
+
+
+ if (!ctx) {
+ const char *lenp;
+ char *endstr = NULL;
+ request_dir_conf *dconf = ap_get_module_config(f->r->per_dir_config,
+ &request_module);
+
+ /* must we step out of the way? */
+ if (!dconf->keep_body || f->r->kept_body) {
+ ap_remove_input_filter(f);
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
+ }
+
+ f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
+
+ /* fail fast if the content length exceeds keep body */
+ lenp = apr_table_get(f->r->headers_in, "Content-Length");
+ if (lenp) {
+
+ /* Protects against over/underflow, non-digit chars in the
+ * string (excluding leading space) (the endstr checks)
+ * and a negative number. */
+ if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10)
+ || endstr == lenp || *endstr || ctx->remaining < 0) {
+
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01411)
+ "Invalid Content-Length");
+
+ ap_remove_input_filter(f);
+ return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
+ }
+
+ /* If we have a limit in effect and we know the C-L ahead of
+ * time, stop it here if it is invalid.
+ */
+ if (dconf->keep_body < ctx->remaining) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01412)
+ "Requested content-length of %" APR_OFF_T_FMT
+ " is larger than the configured limit"
+ " of %" APR_OFF_T_FMT, ctx->remaining, dconf->keep_body);
+ ap_remove_input_filter(f);
+ return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
+ }
+
+ }
+
+ f->r->kept_body = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc);
+ ctx->remaining = dconf->keep_body;
+
+ }
+
+ /* get the brigade from upstream, and read it in to get its length */
+ rv = ap_get_brigade(f->next, b, mode, block, readbytes);
+ if (rv == APR_SUCCESS) {
+ rv = apr_brigade_length(b, 1, &len);
+ }
+
+ /* does the length take us over the limit? */
+ if (APR_SUCCESS == rv && len > ctx->remaining) {
+ if (f->r->kept_body) {
+ apr_brigade_cleanup(f->r->kept_body);
+ f->r->kept_body = NULL;
+ }
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01413)
+ "Requested content-length of %" APR_OFF_T_FMT
+ " is larger than the configured limit"
+ " of %" APR_OFF_T_FMT, len, ctx->keep_body);
+ return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
+ }
+ ctx->remaining -= len;
+
+ /* pass any errors downstream */
+ if (rv != APR_SUCCESS) {
+ if (f->r->kept_body) {
+ apr_brigade_cleanup(f->r->kept_body);
+ f->r->kept_body = NULL;
+ }
+ return rv;
+ }
+
+ /* all is well, set aside the buckets */
+ for (bucket = APR_BRIGADE_FIRST(b);
+ bucket != APR_BRIGADE_SENTINEL(b);
+ bucket = APR_BUCKET_NEXT(bucket))
+ {
+ apr_bucket_copy(bucket, &e);
+ APR_BRIGADE_INSERT_TAIL(f->r->kept_body, e);
+ }
+
+ return APR_SUCCESS;
+}
+
+
+typedef struct kept_body_filter_ctx {
+ apr_off_t offset;
+ apr_off_t remaining;
+} kept_body_ctx_t;
+
+/**
+ * Initialisation of filter to handle a kept body on subrequests.
+ *
+ * If a body is to be reinserted into a subrequest, any chunking will have
+ * been removed from the body during storage. We need to change the request
+ * from Transfer-Encoding: chunked to an explicit Content-Length.
+ */
+static int kept_body_filter_init(ap_filter_t *f) {
+ apr_off_t length = 0;
+ request_rec *r = f->r;
+ apr_bucket_brigade *kept_body = r->kept_body;
+
+ if (kept_body) {
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
+ apr_brigade_length(kept_body, 1, &length);
+ apr_table_setn(r->headers_in, "Content-Length", apr_off_t_toa(r->pool, length));
+ }
+
+ return OK;
+}
+
+/**
+ * Filter to handle a kept body on subrequests.
+ *
+ * If a body has been previously kept by the request, and if a subrequest wants
+ * to re-insert the body into the request, this input filter makes it happen.
+ */
+static apr_status_t kept_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t readbytes)
+{
+ request_rec *r = f->r;
+ apr_bucket_brigade *kept_body = r->kept_body;
+ kept_body_ctx_t *ctx = f->ctx;
+ apr_bucket *ec, *e2;
+ apr_status_t rv;
+
+ /* just get out of the way of things we don't want. */
+ if (!kept_body || (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE)) {
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
+ }
+
+ /* set up the context if it does not already exist */
+ if (!ctx) {
+ f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
+ ctx->offset = 0;
+ apr_brigade_length(kept_body, 1, &ctx->remaining);
+ }
+
+ /* kept_body is finished, send next filter */
+ if (ctx->remaining <= 0) {
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
+ }
+
+ /* send all of the kept_body, but no more */
+ if (readbytes > ctx->remaining) {
+ readbytes = ctx->remaining;
+ }
+
+ /* send part of the kept_body */
+ if ((rv = apr_brigade_partition(kept_body, ctx->offset, &ec)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01414)
+ "apr_brigade_partition() failed on kept_body at %" APR_OFF_T_FMT, ctx->offset);
+ return rv;
+ }
+ if ((rv = apr_brigade_partition(kept_body, ctx->offset + readbytes, &e2)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01415)
+ "apr_brigade_partition() failed on kept_body at %" APR_OFF_T_FMT, ctx->offset + readbytes);
+ return rv;
+ }
+
+ do {
+ apr_bucket *foo;
+ const char *str;
+ apr_size_t len;
+
+ if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) {
+ /* As above; this should not fail since the bucket has
+ * a known length, but just to be sure, this takes
+ * care of uncopyable buckets that do somehow manage
+ * to slip through. */
+ /* XXX: check for failure? */
+ apr_bucket_read(ec, &str, &len, APR_BLOCK_READ);
+ apr_bucket_copy(ec, &foo);
+ }
+ APR_BRIGADE_INSERT_TAIL(b, foo);
+ ec = APR_BUCKET_NEXT(ec);
+ } while (ec != e2);
+
+ ctx->remaining -= readbytes;
+ ctx->offset += readbytes;
+ return APR_SUCCESS;
+
+}
+
+/**
+ * Check whether this filter is not already present.
+ */
+static int request_is_filter_present(request_rec * r, ap_filter_rec_t *fn)
+{
+ ap_filter_t * f = r->input_filters;
+ while (f) {
+ if (f->frec == fn) {
+ return 1;
+ }
+ f = f->next;
+ }
+ return 0;
+}
+
+/**
+ * Insert filter hook.
+ *
+ * Add the KEEP_BODY filter to the request, if the admin wants to keep
+ * the body using the KeptBodySize directive.
+ *
+ * As a precaution, any pre-existing instances of either the kept_body or
+ * keep_body filters will be removed before the filter is added.
+ *
+ * @param r The request
+ */
+static void ap_request_insert_filter(request_rec * r)
+{
+ request_dir_conf *conf = ap_get_module_config(r->per_dir_config,
+ &request_module);
+
+ if (r->kept_body) {
+ if (!request_is_filter_present(r, kept_body_input_filter_handle)) {
+ ap_add_input_filter_handle(kept_body_input_filter_handle,
+ NULL, r, r->connection);
+ }
+ }
+ else if (conf->keep_body) {
+ if (!request_is_filter_present(r, kept_body_input_filter_handle)) {
+ ap_add_input_filter_handle(keep_body_input_filter_handle,
+ NULL, r, r->connection);
+ }
+ }
+
+}
+
+/**
+ * Remove the kept_body and keep body filters from this specific request.
+ */
+static void ap_request_remove_filter(request_rec * r)
+{
+ ap_filter_t * f = r->input_filters;
+ while (f) {
+ if (f->frec->filter_func.in_func == kept_body_filter ||
+ f->frec->filter_func.in_func == keep_body_filter) {
+ ap_remove_input_filter(f);
+ }
+ f = f->next;
+ }
+}
+
+static void *create_request_dir_config(apr_pool_t *p, char *dummy)
+{
+ request_dir_conf *new =
+ (request_dir_conf *) apr_pcalloc(p, sizeof(request_dir_conf));
+
+ new->keep_body_set = 0; /* unset */
+ new->keep_body = 0; /* don't by default */
+
+ return (void *) new;
+}
+
+static void *merge_request_dir_config(apr_pool_t *p, void *basev, void *addv)
+{
+ request_dir_conf *new = (request_dir_conf *) apr_pcalloc(p, sizeof(request_dir_conf));
+ request_dir_conf *add = (request_dir_conf *) addv;
+ request_dir_conf *base = (request_dir_conf *) basev;
+
+ new->keep_body = (add->keep_body_set == 0) ? base->keep_body : add->keep_body;
+ new->keep_body_set = add->keep_body_set || base->keep_body_set;
+
+ return new;
+}
+
+static const char *set_kept_body_size(cmd_parms *cmd, void *dconf,
+ const char *arg)
+{
+ request_dir_conf *conf = dconf;
+ char *end = NULL;
+
+ if (APR_SUCCESS != apr_strtoff(&(conf->keep_body), arg, &end, 10)
+ || conf->keep_body < 0 || end) {
+ return "KeptBodySize must be a valid size in bytes, or zero.";
+ }
+ conf->keep_body_set = 1;
+
+ return NULL;
+}
+
+static const command_rec request_cmds[] = {
+ AP_INIT_TAKE1("KeptBodySize", set_kept_body_size, NULL, ACCESS_CONF,
+ "Maximum size of request bodies kept aside for use by filters"),
+ { NULL }
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+ keep_body_input_filter_handle =
+ ap_register_input_filter(KEEP_BODY_FILTER, keep_body_filter,
+ NULL, AP_FTYPE_RESOURCE);
+ kept_body_input_filter_handle =
+ ap_register_input_filter(KEPT_BODY_FILTER, kept_body_filter,
+ kept_body_filter_init, AP_FTYPE_RESOURCE);
+ ap_hook_insert_filter(ap_request_insert_filter, NULL, NULL, APR_HOOK_LAST);
+ APR_REGISTER_OPTIONAL_FN(ap_request_insert_filter);
+ APR_REGISTER_OPTIONAL_FN(ap_request_remove_filter);
+}
+
+AP_DECLARE_MODULE(request) = {
+ STANDARD20_MODULE_STUFF,
+ create_request_dir_config, /* create per-directory config structure */
+ merge_request_dir_config, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ request_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/filters/mod_request.dsp b/modules/filters/mod_request.dsp
new file mode 100644
index 00000000..4032e008
--- /dev/null
+++ b/modules/filters/mod_request.dsp
@@ -0,0 +1,115 @@
+# Microsoft Developer Studio Project File - Name="mod_request" - 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_request - Win32 Release
+!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_request.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_request.mak" CFG="mod_request - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_request - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_request - 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_request - 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 "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_request_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_request.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_request.so" /d LONG_NAME="request_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_request.so" /base:@..\..\os\win32\BaseAddr.ref,mod_request.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_request.so" /base:@..\..\os\win32\BaseAddr.ref,mod_request.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_request.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_request - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_request_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_request.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_request.so" /d LONG_NAME="request_module for Apache"
+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 /out:".\Debug\mod_request.so" /base:@..\..\os\win32\BaseAddr.ref,mod_request.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_request.so" /base:@..\..\os\win32\BaseAddr.ref,mod_request.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_request.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_request - Win32 Release"
+# Name "mod_request - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\include\mod_request.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_request.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
new file mode 100644
index 00000000..dd776c48
--- /dev/null
+++ b/modules/filters/mod_sed.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * 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.
+ */
+
+#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 "libsed.h"
+
+static const char *sed_filter_name = "Sed";
+#define MODSED_OUTBUF_SIZE 8000
+#define MAX_TRANSIENT_BUCKETS 50
+
+typedef struct sed_expr_config
+{
+ sed_commands_t *sed_cmds;
+ const char *last_error;
+} sed_expr_config;
+
+typedef struct sed_config
+{
+ sed_expr_config output;
+ sed_expr_config input;
+} sed_config;
+
+/* Context for filter invocation for single HTTP request */
+typedef struct sed_filter_ctxt
+{
+ sed_eval_t eval;
+ ap_filter_t *f;
+ request_rec *r;
+ apr_bucket_brigade *bb;
+ apr_bucket_brigade *bbinp;
+ char *outbuf;
+ char *curoutbuf;
+ int bufsize;
+ apr_pool_t *tpool;
+ int numbuckets;
+} sed_filter_ctxt;
+
+module AP_MODULE_DECLARE_DATA sed_module;
+
+/* This function will be call back from libsed functions if there is any error
+ * happend during execution of sed scripts
+ */
+static apr_status_t log_sed_errf(void *data, const char *error)
+{
+ request_rec *r = (request_rec *) data;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", error);
+ return APR_SUCCESS;
+}
+
+/* This function will be call back from libsed functions if there is any
+ * compilation error.
+ */
+static apr_status_t sed_compile_errf(void *data, const char *error)
+{
+ sed_expr_config *sed_cfg = (sed_expr_config *) data;
+ sed_cfg->last_error = error;
+ return APR_SUCCESS;
+}
+
+/* clear the temporary pool (used for transient buckets)
+ */
+static void clear_ctxpool(sed_filter_ctxt* ctx)
+{
+ apr_pool_clear(ctx->tpool);
+ ctx->outbuf = NULL;
+ ctx->curoutbuf = NULL;
+ ctx->numbuckets = 0;
+}
+
+/* alloc_outbuf
+ * allocate output buffer
+ */
+static void alloc_outbuf(sed_filter_ctxt* ctx)
+{
+ ctx->outbuf = apr_palloc(ctx->tpool, ctx->bufsize + 1);
+ ctx->curoutbuf = ctx->outbuf;
+}
+
+/* append_bucket
+ * Allocate a new bucket from buf and sz and append to ctx->bb
+ */
+static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
+{
+ apr_status_t status = APR_SUCCESS;
+ apr_bucket *b;
+ if (ctx->tpool == ctx->r->pool) {
+ /* We are not using transient bucket */
+ b = apr_bucket_pool_create(buf, sz, ctx->r->pool,
+ ctx->r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+ }
+ else {
+ /* We are using transient bucket */
+ b = apr_bucket_transient_create(buf, sz,
+ ctx->r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+ ctx->numbuckets++;
+ if (ctx->numbuckets >= MAX_TRANSIENT_BUCKETS) {
+ b = apr_bucket_flush_create(ctx->r->connection->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+ status = ap_pass_brigade(ctx->f->next, ctx->bb);
+ apr_brigade_cleanup(ctx->bb);
+ clear_ctxpool(ctx);
+ }
+ }
+ return status;
+}
+
+/*
+ * flush_output_buffer
+ * Flush the output data (stored in ctx->outbuf)
+ */
+static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
+{
+ int size = ctx->curoutbuf - ctx->outbuf;
+ char *out;
+ apr_status_t status = APR_SUCCESS;
+ if ((ctx->outbuf == NULL) || (size <=0))
+ return status;
+ out = apr_pmemdup(ctx->tpool, ctx->outbuf, size);
+ status = append_bucket(ctx, out, size);
+ ctx->curoutbuf = ctx->outbuf;
+ return status;
+}
+
+/* This is a call back function. When libsed wants to generate the output,
+ * this function will be invoked.
+ */
+static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
+{
+ /* dummy is basically filter context. Context is passed during invocation
+ * of sed_eval_buffer
+ */
+ int remainbytes = 0;
+ apr_status_t status = APR_SUCCESS;
+ sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
+ if (ctx->outbuf == NULL) {
+ alloc_outbuf(ctx);
+ }
+ remainbytes = ctx->bufsize - (ctx->curoutbuf - ctx->outbuf);
+ if (sz >= remainbytes) {
+ if (remainbytes > 0) {
+ memcpy(ctx->curoutbuf, buf, remainbytes);
+ buf += remainbytes;
+ sz -= remainbytes;
+ ctx->curoutbuf += remainbytes;
+ }
+ /* buffer is now full */
+ status = append_bucket(ctx, ctx->outbuf, ctx->bufsize);
+ /* old buffer is now used so allocate new buffer */
+ alloc_outbuf(ctx);
+ /* if size is bigger than the allocated buffer directly add to output
+ * brigade */
+ if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) {
+ char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
+ status = append_bucket(ctx, newbuf, sz);
+ /* pool might get clear after append_bucket */
+ if (ctx->outbuf == NULL) {
+ alloc_outbuf(ctx);
+ }
+ }
+ else {
+ memcpy(ctx->curoutbuf, buf, sz);
+ ctx->curoutbuf += sz;
+ }
+ }
+ else {
+ memcpy(ctx->curoutbuf, buf, sz);
+ ctx->curoutbuf += sz;
+ }
+ return status;
+}
+
+/* Compile a sed expression. Compiled context is saved in sed_cfg->sed_cmds.
+ * Memory required for compilation context is allocated from cmd->pool.
+ */
+static apr_status_t compile_sed_expr(sed_expr_config *sed_cfg,
+ cmd_parms *cmd,
+ const char *expr)
+{
+ apr_status_t status = APR_SUCCESS;
+
+ if (!sed_cfg->sed_cmds) {
+ sed_commands_t *sed_cmds;
+ sed_cmds = apr_pcalloc(cmd->pool, sizeof(sed_commands_t));
+ status = sed_init_commands(sed_cmds, sed_compile_errf, sed_cfg,
+ cmd->pool);
+ if (status != APR_SUCCESS) {
+ sed_destroy_commands(sed_cmds);
+ return status;
+ }
+ sed_cfg->sed_cmds = sed_cmds;
+ }
+ status = sed_compile_string(sed_cfg->sed_cmds, expr);
+ if (status != APR_SUCCESS) {
+ sed_destroy_commands(sed_cfg->sed_cmds);
+ sed_cfg->sed_cmds = NULL;
+ }
+ return status;
+}
+
+/* sed eval cleanup function */
+static apr_status_t sed_eval_cleanup(void *data)
+{
+ sed_eval_t *eval = (sed_eval_t *) data;
+ sed_destroy_eval(eval);
+ return APR_SUCCESS;
+}
+
+/* Initialize sed filter context. If successful then context is set in f->ctx
+ */
+static apr_status_t init_context(ap_filter_t *f, sed_expr_config *sed_cfg, int usetpool)
+{
+ apr_status_t status;
+ sed_filter_ctxt* ctx;
+ request_rec *r = f->r;
+ /* Create the context. Call sed_init_eval. libsed will generated
+ * output by calling sed_write_output and generates any error by
+ * invoking log_sed_errf.
+ */
+ ctx = apr_pcalloc(r->pool, sizeof(sed_filter_ctxt));
+ ctx->r = r;
+ ctx->bb = NULL;
+ ctx->numbuckets = 0;
+ ctx->f = f;
+ status = sed_init_eval(&ctx->eval, sed_cfg->sed_cmds, log_sed_errf,
+ r, &sed_write_output, r->pool);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ apr_pool_cleanup_register(r->pool, &ctx->eval, sed_eval_cleanup,
+ apr_pool_cleanup_null);
+ ctx->bufsize = MODSED_OUTBUF_SIZE;
+ if (usetpool) {
+ apr_pool_create(&(ctx->tpool), r->pool);
+ }
+ else {
+ ctx->tpool = r->pool;
+ }
+ alloc_outbuf(ctx);
+ f->ctx = ctx;
+ return APR_SUCCESS;
+}
+
+/* Entry function for Sed output filter */
+static apr_status_t sed_response_filter(ap_filter_t *f,
+ apr_bucket_brigade *bb)
+{
+ apr_bucket *b;
+ apr_status_t status;
+ sed_config *cfg = ap_get_module_config(f->r->per_dir_config,
+ &sed_module);
+ sed_filter_ctxt *ctx = f->ctx;
+ sed_expr_config *sed_cfg = &cfg->output;
+
+ if ((sed_cfg == NULL) || (sed_cfg->sed_cmds == NULL)) {
+ /* No sed expressions */
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ if (ctx == NULL) {
+
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
+ /* no need to run sed filter for Head requests */
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
+ status = init_context(f, sed_cfg, 1);
+ if (status != APR_SUCCESS)
+ return status;
+ ctx = f->ctx;
+ apr_table_unset(f->r->headers_out, "Content-Length");
+ }
+
+ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+
+ /* Here is the main logic. Iterate through all the buckets, read the
+ * content of the bucket, call sed_eval_buffer on the data.
+ * sed_eval_buffer will read the data line by line, run filters on each
+ * line. sed_eval_buffer will generates the output by calling
+ * sed_write_output which will add the output to ctx->bb. At the end of
+ * the loop, ctx->bb is passed to the next filter in chain. At the end of
+ * the data, if new line is not found then sed_eval_buffer will store the
+ * data in its own buffer.
+ *
+ * Once eos bucket is found then sed_finalize_eval will flush the rest of
+ * the data. If there is no new line in last line of data, new line is
+ * appended (that is a solaris sed behavior). libsed's internal memory for
+ * evaluation is allocated on request's pool so it will be cleared once
+ * request is over.
+ *
+ * If flush bucket is found then append the the flush bucket to ctx->bb
+ * and pass it to next filter. There may be some data which will still be
+ * in sed's internal buffer which can't be flushed until new line
+ * character is arrived.
+ */
+ for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb);) {
+ const char *buf = NULL;
+ apr_size_t bytes = 0;
+ if (APR_BUCKET_IS_EOS(b)) {
+ apr_bucket *b1 = APR_BUCKET_NEXT(b);
+ /* Now clean up the internal sed buffer */
+ sed_finalize_eval(&ctx->eval, ctx);
+ status = flush_output_buffer(ctx);
+ if (status != APR_SUCCESS) {
+ clear_ctxpool(ctx);
+ return status;
+ }
+ APR_BUCKET_REMOVE(b);
+ /* Insert the eos bucket to ctx->bb brigade */
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+ b = b1;
+ }
+ else if (APR_BUCKET_IS_FLUSH(b)) {
+ apr_bucket *b1 = APR_BUCKET_NEXT(b);
+ APR_BUCKET_REMOVE(b);
+ status = flush_output_buffer(ctx);
+ if (status != APR_SUCCESS) {
+ clear_ctxpool(ctx);
+ return status;
+ }
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+ b = b1;
+ }
+ else if (APR_BUCKET_IS_METADATA(b)) {
+ b = APR_BUCKET_NEXT(b);
+ }
+ else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
+ == APR_SUCCESS) {
+ apr_bucket *b1 = APR_BUCKET_NEXT(b);
+ status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
+ if (status != APR_SUCCESS) {
+ clear_ctxpool(ctx);
+ return status;
+ }
+ APR_BUCKET_REMOVE(b);
+ apr_bucket_delete(b);
+ b = b1;
+ }
+ else {
+ apr_bucket *b1 = APR_BUCKET_NEXT(b);
+ APR_BUCKET_REMOVE(b);
+ b = b1;
+ }
+ }
+ apr_brigade_cleanup(bb);
+ status = flush_output_buffer(ctx);
+ if (status != APR_SUCCESS) {
+ clear_ctxpool(ctx);
+ return status;
+ }
+ if (!APR_BRIGADE_EMPTY(ctx->bb)) {
+ status = ap_pass_brigade(f->next, ctx->bb);
+ apr_brigade_cleanup(ctx->bb);
+ }
+ clear_ctxpool(ctx);
+ return status;
+}
+
+/* Entry function for Sed input filter */
+static apr_status_t sed_request_filter(ap_filter_t *f,
+ apr_bucket_brigade *bb,
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t readbytes)
+{
+ sed_config *cfg = ap_get_module_config(f->r->per_dir_config,
+ &sed_module);
+ sed_filter_ctxt *ctx = f->ctx;
+ apr_status_t status;
+ apr_bucket_brigade *bbinp;
+ sed_expr_config *sed_cfg = &cfg->input;
+
+ if (mode != AP_MODE_READBYTES) {
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
+ }
+
+ if ((sed_cfg == NULL) || (sed_cfg->sed_cmds == NULL)) {
+ /* No sed expression */
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
+ }
+
+ if (!ctx) {
+ if (!ap_is_initial_req(f->r)) {
+ ap_remove_input_filter(f);
+ /* XXX : Should we filter the sub requests too */
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
+ }
+ status = init_context(f, sed_cfg, 0);
+ if (status != APR_SUCCESS)
+ return status;
+ ctx = f->ctx;
+ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+ ctx->bbinp = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
+ }
+
+ bbinp = ctx->bbinp;
+
+ /* Here is the logic :
+ * Read the readbytes data from next level fiter into bbinp. Loop through
+ * the buckets in bbinp and read the data from buckets and invoke
+ * sed_eval_buffer on the data. libsed will generate its output using
+ * sed_write_output which will add data in ctx->bb. Do it until it have
+ * atleast one bucket bucket in ctx->bb. At the end of data eos bucket
+ * should be there.
+ *
+ * Once eos bucket is seen, then invoke sed_finalize_eval to clear the
+ * output. If the last byte of data is not a new line character then sed
+ * will add a new line to the data that is default sed behaviour. Note
+ * that using this filter with POST data, caller may not expect this
+ * behaviour.
+ *
+ * If next level fiter generate the flush bucket, we can't do much about
+ * it. If we want to return the flush bucket in brigade bb (to the caller)
+ * the question is where to add it?
+ */
+ while (APR_BRIGADE_EMPTY(ctx->bb)) {
+ apr_bucket *b;
+
+ /* read the bytes from next level filter */
+ apr_brigade_cleanup(bbinp);
+ status = ap_get_brigade(f->next, bbinp, mode, block, readbytes);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ for (b = APR_BRIGADE_FIRST(bbinp); b != APR_BRIGADE_SENTINEL(bbinp);
+ b = APR_BUCKET_NEXT(b)) {
+ const char *buf = NULL;
+ apr_size_t bytes;
+
+ if (APR_BUCKET_IS_EOS(b)) {
+ /* eos bucket. Clear the internal sed buffers */
+ sed_finalize_eval(&ctx->eval, ctx);
+ flush_output_buffer(ctx);
+ APR_BUCKET_REMOVE(b);
+ APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
+ break;
+ }
+ else if (APR_BUCKET_IS_FLUSH(b)) {
+ /* What should we do with flush bucket */
+ continue;
+ }
+ if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
+ == APR_SUCCESS) {
+ status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx);
+ if (status != APR_SUCCESS)
+ return status;
+ flush_output_buffer(ctx);
+ }
+ }
+ }
+
+ if (!APR_BRIGADE_EMPTY(ctx->bb)) {
+ apr_bucket *b = NULL;
+
+ if (apr_brigade_partition(ctx->bb, readbytes, &b) == APR_INCOMPLETE) {
+ APR_BRIGADE_CONCAT(bb, ctx->bb);
+ }
+ else {
+ APR_BRIGADE_CONCAT(bb, ctx->bb);
+ apr_brigade_split_ex(bb, b, ctx->bb);
+ }
+ }
+ return APR_SUCCESS;
+}
+
+static const char *sed_add_expr(cmd_parms *cmd, void *cfg, const char *arg)
+{
+ int offset = (int) (long) cmd->info;
+ sed_expr_config *sed_cfg =
+ (sed_expr_config *) (((char *) cfg) + offset);
+ if (compile_sed_expr(sed_cfg, cmd, arg) != APR_SUCCESS) {
+ return apr_psprintf(cmd->temp_pool,
+ "Failed to compile sed expression. %s",
+ sed_cfg->last_error);
+ }
+ return NULL;
+}
+
+static void *create_sed_dir_config(apr_pool_t *p, char *s)
+{
+ sed_config *cfg = apr_pcalloc(p, sizeof(sed_config));
+ return cfg;
+}
+
+static const command_rec sed_filter_cmds[] = {
+ AP_INIT_TAKE1("OutputSed", sed_add_expr,
+ (void *) APR_OFFSETOF(sed_config, output),
+ ACCESS_CONF,
+ "Sed regular expression for Response"),
+ AP_INIT_TAKE1("InputSed", sed_add_expr,
+ (void *) APR_OFFSETOF(sed_config, input),
+ ACCESS_CONF,
+ "Sed regular expression for Request"),
+ {NULL}
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_register_output_filter(sed_filter_name, sed_response_filter, NULL,
+ AP_FTYPE_RESOURCE);
+ ap_register_input_filter(sed_filter_name, sed_request_filter, NULL,
+ AP_FTYPE_RESOURCE);
+}
+
+AP_DECLARE_MODULE(sed) = {
+ STANDARD20_MODULE_STUFF,
+ create_sed_dir_config, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ sed_filter_cmds, /* command table */
+ register_hooks /* register hooks */
+};
diff --git a/modules/filters/mod_sed.dsp b/modules/filters/mod_sed.dsp
new file mode 100644
index 00000000..800dfa10
--- /dev/null
+++ b/modules/filters/mod_sed.dsp
@@ -0,0 +1,135 @@
+# Microsoft Developer Studio Project File - Name="mod_sed" - 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_sed - 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_sed.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For substitute:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_sed.mak" CFG="mod_sed - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_sed - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_sed - 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_sed - 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 "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_sed_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_sed.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_sed.so" /d LONG_NAME="substitute_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_sed.so" /base:@..\..\os\win32\BaseAddr.ref,mod_sed.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_sed.so" /base:@..\..\os\win32\BaseAddr.ref,mod_sed.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_sed.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_sed - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_sed_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_sed.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_sed.so" /d LONG_NAME="substitute_module for Apache"
+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 /out:".\Debug\mod_sed.so" /base:@..\..\os\win32\BaseAddr.ref,mod_sed.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_sed.so" /base:@..\..\os\win32\BaseAddr.ref,mod_sed.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_sed.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_sed - Win32 Release"
+# Name "mod_sed - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\libsed.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_sed.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regexp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\regexp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sed.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sed0.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sed1.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c
index 07030403..15cd8ee4 100644
--- a/modules/filters/mod_substitute.c
+++ b/modules/filters/mod_substitute.c
@@ -21,11 +21,13 @@
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
+#include "http_log.h"
#include "apr_general.h"
#include "apr_strings.h"
#include "apr_strmatch.h"
#include "apr_lib.h"
#include "util_filter.h"
+#include "util_varbuf.h"
#include "apr_buckets.h"
#include "http_request.h"
#define APR_WANT_STRFUNC
@@ -78,17 +80,11 @@ static void *merge_substitute_dcfg(apr_pool_t *p, void *basev, void *overv)
}
#define AP_MAX_BUCKETS 1000
-
-#define SEDSCAT(s1, s2, pool, buff, blen, repl) do { \
- if (!s1) { \
- s1 = apr_pstrmemdup(pool, buff, blen); \
- } \
- else { \
- s2 = apr_pstrmemdup(pool, buff, blen); \
- s1 = apr_pstrcat(pool, s1, s2, NULL); \
- } \
- s1 = apr_pstrcat(pool, s1, repl, NULL); \
-} while (0)
+/*
+ * We want to limit the memory usage in a way that is predictable. Therefore
+ * we limit the resulting length of the line to this value.
+ */
+#define AP_SUBST_MAX_LINE_LENGTH (128*MAX_STRING_LEN)
#define SEDRMPATBCKT(b, offset, tmp_b, patlen) do { \
apr_bucket_split(b, offset); \
@@ -98,25 +94,19 @@ static void *merge_substitute_dcfg(apr_pool_t *p, void *basev, void *overv)
apr_bucket_delete(tmp_b); \
} while (0)
-static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
- apr_bucket_brigade *mybb,
- apr_pool_t *tmp_pool)
+static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb,
+ apr_bucket_brigade *mybb,
+ apr_pool_t *pool)
{
int i;
int force_quick = 0;
ap_regmatch_t regm[AP_MAX_REG_MATCH];
apr_size_t bytes;
apr_size_t len;
- apr_size_t fbytes;
const char *buff;
- const char *repl;
- char *scratch;
- char *p;
- char *s1;
- char *s2;
+ struct ap_varbuf vb;
apr_bucket *b;
apr_bucket *tmp_b;
- apr_pool_t *tpool;
subst_dir_conf *cfg =
(subst_dir_conf *) ap_get_module_config(f->r->per_dir_config,
@@ -124,11 +114,9 @@ static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
subst_pattern_t *script;
APR_BRIGADE_INSERT_TAIL(mybb, inb);
-
+ ap_varbuf_init(pool, &vb, 0);
+
script = (subst_pattern_t *) cfg->patterns->elts;
- apr_pool_create(&tpool, tmp_pool);
- scratch = NULL;
- fbytes = 0;
/*
* Simple optimization. If we only have one pattern, then
* we can safely avoid the overhead of flattening
@@ -149,10 +137,19 @@ static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
}
if (apr_bucket_read(b, &buff, &bytes, APR_BLOCK_READ)
== APR_SUCCESS) {
- s1 = NULL;
+ int have_match = 0;
+ vb.strlen = 0;
if (script->pattern) {
+ const char *repl;
+ /*
+ * space_left counts how many bytes we have left until the
+ * line length reaches AP_SUBST_MAX_LINE_LENGTH.
+ */
+ apr_size_t space_left = AP_SUBST_MAX_LINE_LENGTH;
+ apr_size_t repl_len = strlen(script->replacement);
while ((repl = apr_strmatch(script->pattern, buff, bytes)))
{
+ have_match = 1;
/* get offset into buff for pattern */
len = (apr_size_t) (repl - buff);
if (script->flatten && !force_quick) {
@@ -164,14 +161,25 @@ static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
* are constanting allocing space and copying
* strings.
*/
- SEDSCAT(s1, s2, tmp_pool, buff, len,
- script->replacement);
+ if (vb.strlen + len + repl_len > AP_SUBST_MAX_LINE_LENGTH)
+ return APR_ENOMEM;
+ ap_varbuf_strmemcat(&vb, buff, len);
+ ap_varbuf_strmemcat(&vb, script->replacement, repl_len);
}
else {
/*
- * We now split off the stuff before the regex
- * as its own bucket, then isolate the pattern
- * and delete it.
+ * The string before the match but after the
+ * previous match (if any) has length 'len'.
+ * Check if we still have space for this string and
+ * the replacement string.
+ */
+ if (space_left < len + repl_len)
+ return APR_ENOMEM;
+ space_left -= len + repl_len;
+ /*
+ * We now split off the string before the match
+ * as its own bucket, then isolate the matched
+ * string and delete it.
*/
SEDRMPATBCKT(b, len, tmp_b, script->patlen);
/*
@@ -189,82 +197,104 @@ static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
bytes -= len;
buff += len;
}
- if (script->flatten && s1 && !force_quick) {
- /*
- * we've finished looking at the bucket, so remove the
- * old one and add in our new one
- */
- s2 = apr_pstrmemdup(tmp_pool, buff, bytes);
- s1 = apr_pstrcat(tmp_pool, s1, s2, NULL);
- tmp_b = apr_bucket_transient_create(s1, strlen(s1),
- f->r->connection->bucket_alloc);
- APR_BUCKET_INSERT_BEFORE(b, tmp_b);
- apr_bucket_delete(b);
- b = tmp_b;
+ if (have_match) {
+ if (script->flatten && !force_quick) {
+ /* XXX: we should check for AP_MAX_BUCKETS here and
+ * XXX: call ap_pass_brigade accordingly
+ */
+ char *copy = ap_varbuf_pdup(pool, &vb, NULL, 0,
+ buff, bytes, &len);
+ tmp_b = apr_bucket_pool_create(copy, len, pool,
+ f->r->connection->bucket_alloc);
+ APR_BUCKET_INSERT_BEFORE(b, tmp_b);
+ apr_bucket_delete(b);
+ b = tmp_b;
+ }
+ else {
+ /*
+ * We want the behaviour to be predictable.
+ * Therefore we try to always error out if the
+ * line length is larger than the limit,
+ * regardless of the content of the line. So,
+ * let's check if the remaining non-matching
+ * string does not exceed the limit.
+ */
+ if (space_left < b->length)
+ return APR_ENOMEM;
+ }
}
-
}
else if (script->regexp) {
- /*
- * we need a null terminated string here :(. To hopefully
- * save time and memory, we don't alloc for each run
- * through, but only if we need to have a larger chunk
- * to save the string to. So we keep track of how much
- * we've allocated and only re-alloc when we need it.
- * NOTE: this screams for a macro.
- */
- if (!scratch || (bytes > (fbytes + 1))) {
- fbytes = bytes + 1;
- scratch = apr_palloc(tpool, fbytes);
- }
- /* reset pointer to the scratch space */
- p = scratch;
- memcpy(p, buff, bytes);
- p[bytes] = '\0';
- while (!ap_regexec(script->regexp, p,
+ int left = bytes;
+ const char *pos = buff;
+ char *repl;
+ apr_size_t space_left = AP_SUBST_MAX_LINE_LENGTH;
+ while (!ap_regexec_len(script->regexp, pos, left,
AP_MAX_REG_MATCH, regm, 0)) {
- /* first, grab the replacement string */
- repl = ap_pregsub(tmp_pool, script->replacement, p,
- AP_MAX_REG_MATCH, regm);
+ apr_status_t rv;
+ have_match = 1;
if (script->flatten && !force_quick) {
- SEDSCAT(s1, s2, tmp_pool, p, regm[0].rm_so, repl);
+ /* copy bytes before the match */
+ if (regm[0].rm_so > 0)
+ ap_varbuf_strmemcat(&vb, pos, regm[0].rm_so);
+ /* add replacement string */
+ rv = ap_varbuf_regsub(&vb, script->replacement, pos,
+ AP_MAX_REG_MATCH, regm,
+ AP_SUBST_MAX_LINE_LENGTH - vb.strlen);
+ if (rv != APR_SUCCESS)
+ return rv;
}
else {
+ apr_size_t repl_len;
+ /* acount for string before the match */
+ if (space_left <= regm[0].rm_so)
+ return APR_ENOMEM;
+ space_left -= regm[0].rm_so;
+ rv = ap_pregsub_ex(pool, &repl,
+ script->replacement, pos,
+ AP_MAX_REG_MATCH, regm,
+ space_left);
+ if (rv != APR_SUCCESS)
+ return rv;
+ repl_len = strlen(repl);
+ space_left -= repl_len;
len = (apr_size_t) (regm[0].rm_eo - regm[0].rm_so);
SEDRMPATBCKT(b, regm[0].rm_so, tmp_b, len);
- tmp_b = apr_bucket_transient_create(repl,
- strlen(repl),
- f->r->connection->bucket_alloc);
+ tmp_b = apr_bucket_transient_create(repl, repl_len,
+ f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
}
/*
- * reset to past what we just did. buff now maps to b
+ * reset to past what we just did. pos now maps to b
* again
*/
- p += regm[0].rm_eo;
+ pos += regm[0].rm_eo;
+ left -= regm[0].rm_eo;
}
- if (script->flatten && s1 && !force_quick) {
- s1 = apr_pstrcat(tmp_pool, s1, p, NULL);
- tmp_b = apr_bucket_transient_create(s1, strlen(s1),
- f->r->connection->bucket_alloc);
+ if (have_match && script->flatten && !force_quick) {
+ char *copy;
+ /* Copy result plus the part after the last match into
+ * a bucket.
+ */
+ copy = ap_varbuf_pdup(pool, &vb, NULL, 0, pos, left,
+ &len);
+ tmp_b = apr_bucket_pool_create(copy, len, pool,
+ f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
apr_bucket_delete(b);
b = tmp_b;
}
-
}
else {
- /* huh? */
+ ap_assert(0);
continue;
}
}
}
script++;
}
-
- apr_pool_destroy(tpool);
-
- return;
+ ap_varbuf_free(&vb);
+ return APR_SUCCESS;
}
static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
@@ -281,7 +311,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
apr_status_t rv;
substitute_module_ctx *ctx = f->ctx;
-
+
/*
* First time around? Create the saved bb that we used for each pass
* through. Note that we can also get here when we explicitly clear ctx,
@@ -349,9 +379,17 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
if (!APR_BRIGADE_EMPTY(ctx->linebb)) {
rv = apr_brigade_pflatten(ctx->linebb, &bflat,
&fbytes, ctx->tpool);
+ if (rv != APR_SUCCESS)
+ goto err;
+ if (fbytes > AP_SUBST_MAX_LINE_LENGTH) {
+ rv = APR_ENOMEM;
+ goto err;
+ }
tmp_b = apr_bucket_transient_create(bflat, fbytes,
f->r->connection->bucket_alloc);
- do_pattmatch(f, tmp_b, ctx->pattbb, ctx->tpool);
+ rv = do_pattmatch(f, tmp_b, ctx->pattbb, ctx->tpool);
+ if (rv != APR_SUCCESS)
+ goto err;
APR_BRIGADE_CONCAT(ctx->passbb, ctx->pattbb);
}
apr_brigade_cleanup(ctx->linebb);
@@ -407,11 +445,22 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
APR_BRIGADE_INSERT_TAIL(ctx->linebb, b);
rv = apr_brigade_pflatten(ctx->linebb, &bflat,
&fbytes, ctx->tpool);
+ if (rv != APR_SUCCESS)
+ goto err;
+ if (fbytes > AP_SUBST_MAX_LINE_LENGTH) {
+ /* Avoid pflattening further lines, we will
+ * abort later on anyway.
+ */
+ rv = APR_ENOMEM;
+ goto err;
+ }
b = apr_bucket_transient_create(bflat, fbytes,
f->r->connection->bucket_alloc);
apr_brigade_cleanup(ctx->linebb);
}
- do_pattmatch(f, b, ctx->pattbb, ctx->tpool);
+ rv = do_pattmatch(f, b, ctx->pattbb, ctx->tpool);
+ if (rv != APR_SUCCESS)
+ goto err;
/*
* Count how many buckets we have in ctx->passbb
* so far. Yes, this is correct we count ctx->passbb
@@ -442,7 +491,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
num = 0;
apr_pool_clear(ctx->tpool);
if (rv != APR_SUCCESS)
- return rv;
+ goto err;
}
b = tmp_b;
}
@@ -461,10 +510,8 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
if (!APR_BRIGADE_EMPTY(ctx->passbb)) {
rv = ap_pass_brigade(f->next, ctx->passbb);
apr_brigade_cleanup(ctx->passbb);
- if (rv != APR_SUCCESS) {
- apr_pool_clear(ctx->tpool);
- return rv;
- }
+ if (rv != APR_SUCCESS)
+ goto err;
}
apr_pool_clear(ctx->tpool);
}
@@ -482,6 +529,12 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
}
return APR_SUCCESS;
+err:
+ if (rv == APR_ENOMEM)
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01328) "Line too long, URI %s",
+ f->r->uri);
+ apr_pool_clear(ctx->tpool);
+ return rv;
}
static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line)
@@ -560,7 +613,7 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line)
if (is_pattern) {
nscript->patlen = strlen(from);
- nscript->pattern = apr_strmatch_precompile(cmd->pool, from,
+ nscript->pattern = apr_strmatch_precompile(cmd->pool, from,
!ignore_case);
}
else {
@@ -587,7 +640,7 @@ static const command_rec substitute_cmds[] = {
{NULL}
};
-module AP_MODULE_DECLARE_DATA substitute_module = {
+AP_DECLARE_MODULE(substitute) = {
STANDARD20_MODULE_STUFF,
create_substitute_dcfg, /* dir config creater */
merge_substitute_dcfg, /* dir merger --- default is to override */
diff --git a/modules/filters/mod_substitute.dep b/modules/filters/mod_substitute.dep
deleted file mode 100644
index 4ae89e5b..00000000
--- a/modules/filters/mod_substitute.dep
+++ /dev/null
@@ -1,29 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by mod_substitute.mak
-
-..\..\build\win32\httpd.rc : \
- "..\..\include\ap_release.h"\
-
-
-.\mod_substitute.c : \
- "..\..\include\ap_config.h"\
- "..\..\include\ap_mmn.h"\
- "..\..\include\ap_regex.h"\
- "..\..\include\ap_release.h"\
- "..\..\include\http_config.h"\
- "..\..\include\http_core.h"\
- "..\..\include\http_request.h"\
- "..\..\include\httpd.h"\
- "..\..\include\os.h"\
- "..\..\include\util_cfgtree.h"\
- "..\..\include\util_filter.h"\
- "..\..\srclib\apr-util\include\apr_hooks.h"\
- "..\..\srclib\apr-util\include\apr_optional.h"\
- "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
- "..\..\srclib\apr-util\include\apr_strmatch.h"\
- "..\..\srclib\apr-util\include\apr_uri.h"\
- "..\..\srclib\apr\include\apr_hash.h"\
- "..\..\srclib\apr\include\apr_lib.h"\
- "..\..\srclib\apr\include\apr_mmap.h"\
- "..\..\srclib\apr\include\apr_poll.h"\
- "..\..\srclib\apr\include\apr_strings.h"\
-
diff --git a/modules/filters/mod_substitute.mak b/modules/filters/mod_substitute.mak
deleted file mode 100644
index 520cdff1..00000000
--- a/modules/filters/mod_substitute.mak
+++ /dev/null
@@ -1,353 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Based on mod_substitute.dsp
-!IF "$(CFG)" == ""
-CFG=mod_substitute - Win32 Debug
-!MESSAGE No configuration specified. Defaulting to mod_substitute - Win32 Debug.
-!ENDIF
-
-!IF "$(CFG)" != "mod_substitute - Win32 Release" && "$(CFG)" != "mod_substitute - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!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_substitute.mak" CFG="mod_substitute - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_substitute - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_substitute - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-
-!IF "$(CFG)" == "mod_substitute - Win32 Release"
-
-OUTDIR=.\Release
-INTDIR=.\Release
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_substitute.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_substitute.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_substitute.obj"
- -@erase "$(INTDIR)\mod_substitute.res"
- -@erase "$(INTDIR)\mod_substitute_src.idb"
- -@erase "$(INTDIR)\mod_substitute_src.pdb"
- -@erase "$(OUTDIR)\mod_substitute.exp"
- -@erase "$(OUTDIR)\mod_substitute.lib"
- -@erase "$(OUTDIR)\mod_substitute.pdb"
- -@erase "$(OUTDIR)\mod_substitute.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_substitute_src" /FD /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_substitute.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_substitute.so" /d LONG_NAME="substitute_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_substitute.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_substitute.pdb" /debug /out:"$(OUTDIR)\mod_substitute.so" /implib:"$(OUTDIR)\mod_substitute.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_substitute.so /opt:ref
-LINK32_OBJS= \
- "$(INTDIR)\mod_substitute.obj" \
- "$(INTDIR)\mod_substitute.res" \
- "..\..\srclib\apr\Release\libapr-1.lib" \
- "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
- "..\..\Release\libhttpd.lib"
-
-"$(OUTDIR)\mod_substitute.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Release\mod_substitute.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Release
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_substitute.so"
- if exist .\Release\mod_substitute.so.manifest mt.exe -manifest .\Release\mod_substitute.so.manifest -outputresource:.\Release\mod_substitute.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ELSEIF "$(CFG)" == "mod_substitute - Win32 Debug"
-
-OUTDIR=.\Debug
-INTDIR=.\Debug
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-!IF "$(RECURSE)" == "0"
-
-ALL : "$(OUTDIR)\mod_substitute.so" "$(DS_POSTBUILD_DEP)"
-
-!ELSE
-
-ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_substitute.so" "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-!IF "$(RECURSE)" == "1"
-CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
-!ELSE
-CLEAN :
-!ENDIF
- -@erase "$(INTDIR)\mod_substitute.obj"
- -@erase "$(INTDIR)\mod_substitute.res"
- -@erase "$(INTDIR)\mod_substitute_src.idb"
- -@erase "$(INTDIR)\mod_substitute_src.pdb"
- -@erase "$(OUTDIR)\mod_substitute.exp"
- -@erase "$(OUTDIR)\mod_substitute.lib"
- -@erase "$(OUTDIR)\mod_substitute.pdb"
- -@erase "$(OUTDIR)\mod_substitute.so"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_substitute_src" /FD /EHsc /c
-
-.c{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.c{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cpp{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-.cxx{$(INTDIR)}.sbr::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
-
-MTL=midl.exe
-MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
-RSC=rc.exe
-RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_substitute.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_substitute.so" /d LONG_NAME="substitute_module for Apache"
-BSC32=bscmake.exe
-BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_substitute.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_substitute.pdb" /debug /out:"$(OUTDIR)\mod_substitute.so" /implib:"$(OUTDIR)\mod_substitute.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_substitute.so
-LINK32_OBJS= \
- "$(INTDIR)\mod_substitute.obj" \
- "$(INTDIR)\mod_substitute.res" \
- "..\..\srclib\apr\Debug\libapr-1.lib" \
- "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
- "..\..\Debug\libhttpd.lib"
-
-"$(OUTDIR)\mod_substitute.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-TargetPath=.\Debug\mod_substitute.so
-SOURCE="$(InputPath)"
-PostBuild_Desc=Embed .manifest
-DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
-
-# Begin Custom Macros
-OutDir=.\Debug
-# End Custom Macros
-
-"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_substitute.so"
- if exist .\Debug\mod_substitute.so.manifest mt.exe -manifest .\Debug\mod_substitute.so.manifest -outputresource:.\Debug\mod_substitute.so;2
- echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
-
-!ENDIF
-
-
-!IF "$(NO_EXTERNAL_DEPS)" != "1"
-!IF EXISTS("mod_substitute.dep")
-!INCLUDE "mod_substitute.dep"
-!ELSE
-!MESSAGE Warning: cannot find "mod_substitute.dep"
-!ENDIF
-!ENDIF
-
-
-!IF "$(CFG)" == "mod_substitute - Win32 Release" || "$(CFG)" == "mod_substitute - Win32 Debug"
-
-!IF "$(CFG)" == "mod_substitute - Win32 Release"
-
-"libapr - Win32 Release" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
- cd "..\..\modules\filters"
-
-"libapr - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_substitute - Win32 Debug"
-
-"libapr - Win32 Debug" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libapr - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr"
- $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_substitute - Win32 Release"
-
-"libaprutil - Win32 Release" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 ReleaseCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_substitute - Win32 Debug"
-
-"libaprutil - Win32 Debug" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
- cd "..\..\modules\filters"
-
-"libaprutil - Win32 DebugCLEAN" :
- cd ".\..\..\srclib\apr-util"
- $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
- cd "..\..\modules\filters"
-
-!ENDIF
-
-!IF "$(CFG)" == "mod_substitute - Win32 Release"
-
-"libhttpd - Win32 Release" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
- cd ".\modules\filters"
-
-"libhttpd - Win32 ReleaseCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ELSEIF "$(CFG)" == "mod_substitute - Win32 Debug"
-
-"libhttpd - Win32 Debug" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
- cd ".\modules\filters"
-
-"libhttpd - Win32 DebugCLEAN" :
- cd ".\..\.."
- $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
- cd ".\modules\filters"
-
-!ENDIF
-
-SOURCE=..\..\build\win32\httpd.rc
-
-!IF "$(CFG)" == "mod_substitute - Win32 Release"
-
-
-"$(INTDIR)\mod_substitute.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_substitute.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_substitute.so" /d LONG_NAME="substitute_module for Apache" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "mod_substitute - Win32 Debug"
-
-
-"$(INTDIR)\mod_substitute.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x409 /fo"$(INTDIR)\mod_substitute.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_substitute.so" /d LONG_NAME="substitute_module for Apache" $(SOURCE)
-
-
-!ENDIF
-
-SOURCE=.\mod_substitute.c
-
-"$(INTDIR)\mod_substitute.obj" : $(SOURCE) "$(INTDIR)"
-
-
-
-!ENDIF
-
diff --git a/modules/filters/mod_xml2enc.c b/modules/filters/mod_xml2enc.c
new file mode 100644
index 00000000..fd544444
--- /dev/null
+++ b/modules/filters/mod_xml2enc.c
@@ -0,0 +1,628 @@
+/* Copyright (c) 2007-11, WebThing Ltd
+ * Copyright (c) 2011-, The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#if defined(WIN32)
+#define XML2ENC_DECLARE_EXPORT
+#endif
+
+#include <ctype.h>
+
+/* libxml2 */
+#include <libxml/encoding.h>
+
+#include "http_protocol.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "apr_strings.h"
+#include "apr_xlate.h"
+
+#include "apr_optional.h"
+#include "mod_xml2enc.h"
+
+module AP_MODULE_DECLARE_DATA xml2enc_module;
+
+#define BUFLEN 8192
+#define BUF_MIN 4096
+#define APR_BRIGADE_DO(b,bb) for (b = APR_BRIGADE_FIRST(bb); \
+ b != APR_BRIGADE_SENTINEL(bb); \
+ b = APR_BUCKET_NEXT(b))
+
+#define ENC_INITIALISED 0x100
+#define ENC_SEEN_EOS 0x200
+#define ENC_SKIPTO ENCIO_SKIPTO
+
+#define HAVE_ENCODING(enc) \
+ (((enc)!=XML_CHAR_ENCODING_NONE)&&((enc)!=XML_CHAR_ENCODING_ERROR))
+
+/*
+ * XXX: Check all those ap_assert()s ans replace those that should not happen
+ * XXX: with AP_DEBUG_ASSERT and those that may happen with proper error
+ * XXX: handling.
+ */
+typedef struct {
+ xmlCharEncoding xml2enc;
+ char* buf;
+ apr_size_t bytes;
+ apr_xlate_t* convset;
+ unsigned int flags;
+ apr_off_t bblen;
+ apr_bucket_brigade* bbnext;
+ apr_bucket_brigade* bbsave;
+ const char* encoding;
+} xml2ctx;
+
+typedef struct {
+ const char* default_charset;
+ xmlCharEncoding default_encoding;
+ apr_array_header_t* skipto;
+} xml2cfg;
+
+typedef struct {
+ const char* val;
+} tattr;
+
+static ap_regex_t* seek_meta_ctype;
+static ap_regex_t* seek_charset;
+
+static apr_status_t xml2enc_filter(request_rec* r, const char* enc,
+ unsigned int mode)
+{
+ /* set up a ready-initialised ctx to convert to enc, and insert filter */
+ apr_xlate_t* convset;
+ apr_status_t rv;
+ unsigned int flags = (mode ^ ENCIO);
+ if ((mode & ENCIO) == ENCIO_OUTPUT) {
+ rv = apr_xlate_open(&convset, enc, "UTF-8", r->pool);
+ flags |= ENC_INITIALISED;
+ }
+ else if ((mode & ENCIO) == ENCIO_INPUT) {
+ rv = apr_xlate_open(&convset, "UTF-8", enc, r->pool);
+ flags |= ENC_INITIALISED;
+ }
+ else if ((mode & ENCIO) == ENCIO_INPUT_CHECKS) {
+ convset = NULL;
+ rv = APR_SUCCESS; /* we'll initialise later by sniffing */
+ }
+ else {
+ rv = APR_EGENERAL;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01426)
+ "xml2enc: bad mode %x", mode);
+ }
+ if (rv == APR_SUCCESS) {
+ xml2ctx* ctx = apr_pcalloc(r->pool, sizeof(xml2ctx));
+ ctx->flags = flags;
+ if (flags & ENC_INITIALISED) {
+ ctx->convset = convset;
+ ctx->bblen = BUFLEN;
+ ctx->buf = apr_palloc(r->pool, (apr_size_t)ctx->bblen);
+ }
+ ap_add_output_filter("xml2enc", ctx, r, r->connection);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01427)
+ "xml2enc: Charset %s not supported.", enc) ;
+ }
+ return rv;
+}
+
+/* This needs to operate only when we're using htmlParser */
+/* Different modules may apply different rules here. Ho, hum. */
+static void fix_skipto(request_rec* r, xml2ctx* ctx)
+{
+ apr_status_t rv;
+ xml2cfg* cfg = ap_get_module_config(r->per_dir_config, &xml2enc_module);
+ if ((cfg->skipto != NULL) && (ctx->flags | ENC_SKIPTO)) {
+ int found = 0;
+ char* p = ap_strchr(ctx->buf, '<');
+ tattr* starts = (tattr*) cfg->skipto->elts;
+ while (!found && p && *p) {
+ int i;
+ for (i = 0; i < cfg->skipto->nelts; ++i) {
+ if (!strncasecmp(p+1, starts[i].val, strlen(starts[i].val))) {
+ /* found a starting element. Strip all that comes before. */
+ apr_bucket* b;
+ apr_bucket* bstart;
+ rv = apr_brigade_partition(ctx->bbsave, (p-ctx->buf),
+ &bstart);
+ ap_assert(rv == APR_SUCCESS);
+ while (b = APR_BRIGADE_FIRST(ctx->bbsave), b != bstart) {
+ APR_BUCKET_REMOVE(b);
+ apr_bucket_destroy(b);
+ }
+ ctx->bytes -= (p-ctx->buf);
+ ctx->buf = p ;
+ found = 1;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01428)
+ "Skipped to first <%s> element",
+ starts[i].val) ;
+ break;
+ }
+ }
+ p = ap_strchr(p+1, '<');
+ }
+ if (p == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01429)
+ "Failed to find start of recognised HTML!");
+ }
+ }
+}
+static void sniff_encoding(request_rec* r, xml2ctx* ctx)
+{
+ xml2cfg* cfg = NULL; /* initialise to shut compiler warnings up */
+ char* p ;
+ apr_bucket* cutb;
+ apr_bucket* cute;
+ apr_bucket* b;
+ ap_regmatch_t match[2] ;
+ apr_status_t rv;
+ const char* ctype = r->content_type;
+
+ if (ctype) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01430)
+ "Content-Type is %s", ctype) ;
+
+ /* If we've got it in the HTTP headers, there's nothing to do */
+ if (ctype && (p = ap_strcasestr(ctype, "charset=") , p != NULL)) {
+ p += 8 ;
+ if (ctx->encoding = apr_pstrndup(r->pool, p, strcspn(p, " ;") ),
+ ctx->encoding) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01431)
+ "Got charset %s from HTTP headers", ctx->encoding) ;
+ ctx->xml2enc = xmlParseCharEncoding(ctx->encoding);
+ }
+ }
+ }
+
+ /* to sniff, first we look for BOM */
+ if (ctx->xml2enc == XML_CHAR_ENCODING_NONE) {
+ ctx->xml2enc = xmlDetectCharEncoding((const xmlChar*)ctx->buf,
+ ctx->bytes);
+ if (HAVE_ENCODING(ctx->xml2enc)) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01432)
+ "Got charset from XML rules.") ;
+ ctx->encoding = xmlGetCharEncodingName(ctx->xml2enc);
+ }
+ }
+
+ /* If none of the above, look for a META-thingey */
+ /* also we're probably about to invalidate it, so we remove it. */
+ if (ap_regexec(seek_meta_ctype, ctx->buf, 1, match, 0) == 0 ) {
+ /* get markers on the start and end of the match */
+ rv = apr_brigade_partition(ctx->bbsave, match[0].rm_eo, &cute);
+ ap_assert(rv == APR_SUCCESS);
+ rv = apr_brigade_partition(ctx->bbsave, match[0].rm_so, &cutb);
+ ap_assert(rv == APR_SUCCESS);
+ /* now set length of useful buf for start-of-data hooks */
+ ctx->bytes = match[0].rm_so;
+ if (ctx->encoding == NULL) {
+ p = apr_pstrndup(r->pool, ctx->buf + match[0].rm_so,
+ match[0].rm_eo - match[0].rm_so) ;
+ if (ap_regexec(seek_charset, p, 2, match, 0) == 0) {
+ if (ctx->encoding = apr_pstrndup(r->pool, p+match[1].rm_so,
+ match[1].rm_eo - match[1].rm_so),
+ ctx->encoding) {
+ ctx->xml2enc = xmlParseCharEncoding(ctx->encoding);
+ if (HAVE_ENCODING(ctx->xml2enc))
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01433)
+ "Got charset %s from HTML META", ctx->encoding) ;
+ }
+ }
+ }
+
+ /* cut out the <meta> we're invalidating */
+ while (cutb != cute) {
+ b = APR_BUCKET_NEXT(cutb);
+ APR_BUCKET_REMOVE(cutb);
+ apr_bucket_destroy(cutb);
+ cutb = b;
+ }
+ /* and leave a string */
+ ctx->buf[ctx->bytes] = 0;
+ }
+
+ /* either it's set to something we found or it's still the default */
+ /* Aaargh! libxml2 has undocumented <META-crap> support. So this fails
+ * if metafix is not active. Have to make it conditional.
+ *
+ * No, that means no-metafix breaks things. Deal immediately with
+ * this particular instance of metafix.
+ */
+ if (!HAVE_ENCODING(ctx->xml2enc)) {
+ cfg = ap_get_module_config(r->per_dir_config, &xml2enc_module);
+ if (!ctx->encoding) {
+ ctx->encoding = cfg->default_charset?cfg->default_charset:"ISO-8859-1";
+ }
+ /* Unsupported charset. Can we get (iconv) support through apr_xlate? */
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01434)
+ "Charset %s not supported by libxml2; trying apr_xlate",
+ ctx->encoding);
+ if (apr_xlate_open(&ctx->convset, "UTF-8", ctx->encoding, r->pool)
+ == APR_SUCCESS) {
+ ctx->xml2enc = XML_CHAR_ENCODING_UTF8 ;
+ } else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01435)
+ "Charset %s not supported. Consider aliasing it?",
+ ctx->encoding) ;
+ }
+ }
+
+ if (!HAVE_ENCODING(ctx->xml2enc)) {
+ /* Use configuration default as a last resort */
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01436)
+ "No usable charset information; using configuration default");
+ ctx->xml2enc = (cfg->default_encoding == XML_CHAR_ENCODING_NONE)
+ ? XML_CHAR_ENCODING_8859_1 : cfg->default_encoding ;
+ }
+ if (ctype && ctx->encoding) {
+ if (ap_regexec(seek_charset, ctype, 2, match, 0)) {
+ r->content_type = apr_pstrcat(r->pool, ctype, ";charset=utf-8",
+ NULL);
+ } else {
+ char* str = apr_palloc(r->pool, strlen(r->content_type) + 13
+ - (match[0].rm_eo - match[0].rm_so) + 1);
+ memcpy(str, r->content_type, match[1].rm_so);
+ memcpy(str + match[1].rm_so, "utf-8", 5);
+ strcpy(str + match[1].rm_so + 5, r->content_type+match[1].rm_eo);
+ r->content_type = str;
+ }
+ }
+}
+
+static apr_status_t xml2enc_filter_init(ap_filter_t* f)
+{
+ xml2ctx* ctx;
+ if (!f->ctx) {
+ xml2cfg* cfg = ap_get_module_config(f->r->per_dir_config,
+ &xml2enc_module);
+ f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(xml2ctx));
+ ctx->xml2enc = XML_CHAR_ENCODING_NONE;
+ if (cfg->skipto != NULL) {
+ ctx->flags |= ENC_SKIPTO;
+ }
+ }
+ return APR_SUCCESS;
+}
+static apr_status_t xml2enc_ffunc(ap_filter_t* f, apr_bucket_brigade* bb)
+{
+ xml2ctx* ctx = f->ctx;
+ apr_status_t rv;
+ apr_bucket* b;
+ apr_bucket* bstart;
+ apr_size_t insz = 0;
+ char *ctype;
+ char *p;
+
+ if (!ctx || !f->r->content_type) {
+ /* log error about configuring this */
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb) ;
+ }
+
+ ctype = apr_pstrdup(f->r->pool, f->r->content_type);
+ for (p = ctype; *p; ++p)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ /* only act if starts-with "text/" or contains "xml" */
+ if (strncmp(ctype, "text/", 5) && !strstr(ctype, "xml")) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb) ;
+ }
+
+ if (ctx->bbsave == NULL) {
+ ctx->bbsave = apr_brigade_create(f->r->pool,
+ f->r->connection->bucket_alloc);
+ }
+ /* append to any data left over from last time */
+ APR_BRIGADE_CONCAT(ctx->bbsave, bb);
+
+ if (!(ctx->flags & ENC_INITIALISED)) {
+ /* some kind of initialisation required */
+ /* Turn all this off when post-processing */
+
+ /* if we don't have enough data to sniff but more's to come, wait */
+ apr_brigade_length(ctx->bbsave, 0, &ctx->bblen);
+ if ((ctx->bblen < BUF_MIN) && (ctx->bblen != -1)) {
+ APR_BRIGADE_DO(b, ctx->bbsave) {
+ if (APR_BUCKET_IS_EOS(b)) {
+ ctx->flags |= ENC_SEEN_EOS;
+ break;
+ }
+ }
+ if (!(ctx->flags & ENC_SEEN_EOS)) {
+ /* not enough data to sniff. Wait for more */
+ APR_BRIGADE_DO(b, ctx->bbsave) {
+ rv = apr_bucket_setaside(b, f->r->pool);
+ ap_assert(rv == APR_SUCCESS);
+ }
+ return APR_SUCCESS;
+ }
+ }
+ if (ctx->bblen == -1) {
+ ctx->bblen = BUFLEN-1;
+ }
+
+ /* flatten it into a NULL-terminated string */
+ ctx->buf = apr_palloc(f->r->pool, (apr_size_t)(ctx->bblen+1));
+ ctx->bytes = (apr_size_t)ctx->bblen;
+ rv = apr_brigade_flatten(ctx->bbsave, ctx->buf, &ctx->bytes);
+ ap_assert(rv == APR_SUCCESS);
+ ctx->buf[ctx->bytes] = 0;
+ sniff_encoding(f->r, ctx);
+
+ /* FIXME: hook here for rewriting start-of-data? */
+ /* nah, we only have one action here - call it inline */
+ fix_skipto(f->r, ctx);
+
+ /* consume the data we just sniffed */
+ /* we need to omit any <meta> we just invalidated */
+ ctx->flags |= ENC_INITIALISED;
+ ap_set_module_config(f->r->request_config, &xml2enc_module, ctx);
+ }
+ if (ctx->bbnext == NULL) {
+ ctx->bbnext = apr_brigade_create(f->r->pool,
+ f->r->connection->bucket_alloc);
+ }
+
+ if (!ctx->convset) {
+ rv = ap_pass_brigade(f->next, ctx->bbsave);
+ apr_brigade_cleanup(ctx->bbsave);
+ ap_remove_output_filter(f);
+ return rv;
+ }
+ /* move the data back to bb */
+ APR_BRIGADE_CONCAT(bb, ctx->bbsave);
+
+ while (b = APR_BRIGADE_FIRST(bb), b != APR_BRIGADE_SENTINEL(bb)) {
+ ctx->bytes = 0;
+ if (APR_BUCKET_IS_METADATA(b)) {
+ if (APR_BUCKET_IS_EOS(b)) {
+ /* send remaining data */
+ return ap_fflush(f->next, ctx->bbnext);
+ } else if (APR_BUCKET_IS_FLUSH(b)) {
+ ap_fflush(f->next, ctx->bbnext);
+ }
+ APR_BUCKET_REMOVE(b);
+ apr_bucket_destroy(b);
+ }
+ else { /* data bucket */
+ char* buf;
+ apr_size_t bytes = 0;
+ char fixbuf[BUFLEN];
+ apr_bucket* bdestroy = NULL;
+ if (insz > 0) { /* we have dangling data. Flatten it. */
+ buf = fixbuf;
+ bytes = BUFLEN;
+ rv = apr_brigade_flatten(bb, buf, &bytes);
+ ap_assert(rv == APR_SUCCESS);
+ if (bytes == insz) {
+ /* this is only what we've already tried to convert.
+ * The brigade is exhausted.
+ * Save remaining data for next time round
+ */
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(01437)
+ "xml2enc: Setting aside %" APR_SIZE_T_FMT
+ " unconverted bytes", bytes);
+ rv = ap_fflush(f->next, ctx->bbnext);
+ APR_BRIGADE_CONCAT(ctx->bbsave, bb);
+ APR_BRIGADE_DO(b, ctx->bbsave) {
+ ap_assert(apr_bucket_setaside(b, f->r->pool)
+ == APR_SUCCESS);
+ }
+ return rv;
+ }
+ /* remove the data we've just read */
+ rv = apr_brigade_partition(bb, bytes, &bstart);
+ while (b = APR_BRIGADE_FIRST(bb), b != bstart) {
+ APR_BUCKET_REMOVE(b);
+ apr_bucket_destroy(b);
+ }
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(01438)
+ "xml2enc: consuming %" APR_SIZE_T_FMT
+ " bytes flattened", bytes);
+ }
+ else {
+ rv = apr_bucket_read(b, (const char**)&buf, &bytes,
+ APR_BLOCK_READ);
+ APR_BUCKET_REMOVE(b);
+ bdestroy = b; /* can't destroy until finished with the data */
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(01439)
+ "xml2enc: consuming %" APR_SIZE_T_FMT
+ " bytes from bucket", bytes);
+ }
+ /* OK, we've got some input we can use in [buf,bytes] */
+ if (rv == APR_SUCCESS) {
+ apr_size_t consumed;
+ xml2enc_run_preprocess(f, &buf, &bytes);
+ consumed = insz = bytes;
+ while (insz > 0) {
+ apr_status_t rv2;
+ if (ctx->bytes == ctx->bblen) {
+ /* nothing was converted last time!
+ * break out of this loop!
+ */
+ b = apr_bucket_transient_create(buf+(bytes - insz), insz,
+ bb->bucket_alloc);
+ APR_BRIGADE_INSERT_HEAD(bb, b);
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(01440)
+ "xml2enc: reinserting %" APR_SIZE_T_FMT
+ " unconsumed bytes from bucket", insz);
+ break;
+ }
+ ctx->bytes = (apr_size_t)ctx->bblen;
+ rv = apr_xlate_conv_buffer(ctx->convset, buf+(bytes - insz),
+ &insz, ctx->buf, &ctx->bytes);
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r, APLOGNO(01441)
+ "xml2enc: converted %" APR_SIZE_T_FMT
+ "/%" APR_OFF_T_FMT " bytes", consumed - insz,
+ ctx->bblen - ctx->bytes);
+ consumed = insz;
+ rv2 = ap_fwrite(f->next, ctx->bbnext, ctx->buf,
+ (apr_size_t)ctx->bblen - ctx->bytes);
+ if (rv2 != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv2, f->r, APLOGNO(01442)
+ "ap_fwrite failed");
+ return rv2;
+ }
+ switch (rv) {
+ case APR_SUCCESS:
+ continue;
+ case APR_EINCOMPLETE:
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(01443)
+ "INCOMPLETE");
+ continue; /* If outbuf too small, go round again.
+ * If it was inbuf, we'll break out when
+ * we test ctx->bytes == ctx->bblen
+ */
+ case APR_EINVAL: /* try skipping one bad byte */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01444)
+ "Skipping invalid byte(s) in input stream!");
+ --insz;
+ continue;
+ default:
+ /* Erk! What's this?
+ * Bail out, flush, and hope to eat the buf raw
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01445)
+ "Failed to convert input; trying it raw") ;
+ ctx->convset = NULL;
+ rv = ap_fflush(f->next, ctx->bbnext);
+ if (rv != APR_SUCCESS)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r, APLOGNO(01446)
+ "ap_fflush failed");
+ else
+ rv = ap_pass_brigade(f->next, ctx->bbnext);
+ }
+ }
+ } else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01447)
+ "xml2enc: error reading data") ;
+ }
+ if (bdestroy)
+ apr_bucket_destroy(bdestroy);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+ }
+ return APR_SUCCESS;
+}
+static apr_status_t xml2enc_charset(request_rec* r, xmlCharEncoding* encp,
+ const char** encoding)
+{
+ xml2ctx* ctx = ap_get_module_config(r->request_config, &xml2enc_module);
+ if (!ctx || !(ctx->flags & ENC_INITIALISED)) {
+ return APR_EAGAIN;
+ }
+ *encp = ctx->xml2enc;
+ *encoding = ctx->encoding;
+ return HAVE_ENCODING(ctx->xml2enc) ? APR_SUCCESS : APR_EGENERAL;
+}
+
+#define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH
+static void xml2enc_hooks(apr_pool_t* pool)
+{
+ ap_register_output_filter_protocol("xml2enc", xml2enc_ffunc,
+ xml2enc_filter_init,
+ AP_FTYPE_RESOURCE, PROTO_FLAGS);
+ APR_REGISTER_OPTIONAL_FN(xml2enc_filter);
+ APR_REGISTER_OPTIONAL_FN(xml2enc_charset);
+ seek_meta_ctype = ap_pregcomp(pool,
+ "(<meta[^>]*http-equiv[ \t\r\n='\"]*content-type[^>]*>)",
+ AP_REG_EXTENDED|AP_REG_ICASE) ;
+ seek_charset = ap_pregcomp(pool, "charset=([A-Za-z0-9_-]+)",
+ AP_REG_EXTENDED|AP_REG_ICASE) ;
+}
+static const char* set_alias(cmd_parms* cmd, void* CFG,
+ const char* charset, const char* alias)
+{
+ const char* errmsg = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (errmsg != NULL)
+ return errmsg ;
+ else if (xmlAddEncodingAlias(charset, alias) == 0)
+ return NULL;
+ else
+ return "Error setting charset alias";
+}
+
+static const char* set_default(cmd_parms* cmd, void* CFG, const char* charset)
+{
+ xml2cfg* cfg = CFG;
+ cfg->default_charset = charset;
+ cfg->default_encoding = xmlParseCharEncoding(charset);
+ switch(cfg->default_encoding) {
+ case XML_CHAR_ENCODING_NONE:
+ return "Default charset not found";
+ case XML_CHAR_ENCODING_ERROR:
+ return "Invalid or unsupported default charset";
+ default:
+ return NULL;
+ }
+}
+static const char* set_skipto(cmd_parms* cmd, void* CFG, const char* arg)
+{
+ tattr* attr;
+ xml2cfg* cfg = CFG;
+ if (cfg->skipto == NULL)
+ cfg->skipto = apr_array_make(cmd->pool, 4, sizeof(tattr));
+ attr = apr_array_push(cfg->skipto) ;
+ attr->val = arg;
+ return NULL;
+}
+
+static const command_rec xml2enc_cmds[] = {
+ AP_INIT_TAKE1("xml2EncDefault", set_default, NULL, OR_ALL,
+ "Usage: xml2EncDefault charset"),
+ AP_INIT_ITERATE2("xml2EncAlias", set_alias, NULL, RSRC_CONF,
+ "EncodingAlias charset alias [more aliases]"),
+ AP_INIT_ITERATE("xml2StartParse", set_skipto, NULL, OR_ALL,
+ "Ignore anything in front of the first of these elements"),
+ { NULL }
+};
+static void* xml2enc_config(apr_pool_t* pool, char* x)
+{
+ xml2cfg* ret = apr_pcalloc(pool, sizeof(xml2cfg));
+ ret->default_encoding = XML_CHAR_ENCODING_NONE ;
+ return ret;
+}
+
+static void* xml2enc_merge(apr_pool_t* pool, void* BASE, void* ADD)
+{
+ xml2cfg* base = BASE;
+ xml2cfg* add = ADD;
+ xml2cfg* ret = apr_pcalloc(pool, sizeof(xml2cfg));
+ ret->default_encoding = (add->default_encoding == XML_CHAR_ENCODING_NONE)
+ ? base->default_encoding : add->default_encoding ;
+ ret->default_charset = add->default_charset
+ ? add->default_charset : base->default_charset;
+ ret->skipto = add->skipto ? add->skipto : base->skipto;
+ return ret;
+}
+module AP_MODULE_DECLARE_DATA xml2enc_module = {
+ STANDARD20_MODULE_STUFF,
+ xml2enc_config,
+ xml2enc_merge,
+ NULL,
+ NULL,
+ xml2enc_cmds,
+ xml2enc_hooks
+};
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(xml2enc, XML2ENC, int, preprocess,
+ (ap_filter_t *f, char** bufp, apr_size_t* bytesp),
+ (f, bufp, bytesp), OK, DECLINED)
diff --git a/modules/filters/mod_xml2enc.dsp b/modules/filters/mod_xml2enc.dsp
new file mode 100644
index 00000000..6ad6ef3a
--- /dev/null
+++ b/modules/filters/mod_xml2enc.dsp
@@ -0,0 +1,123 @@
+# Microsoft Developer Studio Project File - Name="mod_xml2enc" - 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_xml2enc - Win32 Release
+!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_xml2enc.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_xml2enc.mak" CFG="mod_xml2enc - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_xml2enc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_xml2enc - 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_xml2enc - 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 "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/libxml2/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_xml2enc_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG" /i "../../include" /i "../../srclib/apr/include" /i "../../srclib/apr-util/include" /i "../../srclib/libxml2/include"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_xml2enc.so" /base:@..\..\os\win32\BaseAddr.ref,mod_xml2enc.so
+# ADD LINK32 kernel32.lib libxml2.lib /nologo /subsystem:windows /dll /incremental:no /debug /libpath:"../../srclib/libxml2/win32/bin.msvc" /out:".\Release\mod_xml2enc.so" /base:@..\..\os\win32\BaseAddr.ref,mod_xml2enc.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_xml2enc.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_xml2enc - 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 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/libxml2/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_xml2enc_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /i /d "_DEBUG" "../../include" /i "../../srclib/apr/include" /i "../../srclib/apr-util/include" /i "../../srclib/libxml2/include"
+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 /out:".\Debug\mod_xml2enc.so" /base:@..\..\os\win32\BaseAddr.ref,mod_xml2enc.so
+# ADD LINK32 kernel32.lib libxml2.lib /nologo /subsystem:windows /dll /incremental:no /debug /libpath:"../../srclib/libxml2/win32/bin.msvc" /out:".\Debug\mod_xml2enc.so" /base:@..\..\os\win32\BaseAddr.ref,mod_xml2enc.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_xml2enc.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_xml2enc - Win32 Release"
+# Name "mod_xml2enc - Win32 Debug"
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h"
+# Begin Source File
+
+SOURCE=.\mod_xml2enc.h
+# End Source File
+# End Group
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\mod_xml2enc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/modules/filters/mod_xml2enc.h b/modules/filters/mod_xml2enc.h
new file mode 100644
index 00000000..90d0e0fa
--- /dev/null
+++ b/modules/filters/mod_xml2enc.h
@@ -0,0 +1,55 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#ifndef MOD_XML2ENC
+#define MOD_XML2ENC
+
+#define ENCIO_INPUT 0x01
+#define ENCIO_OUTPUT 0x02
+#define ENCIO_INPUT_CHECKS 0x04
+#define ENCIO (ENCIO_INPUT|ENCIO_OUTPUT|ENCIO_INPUT_CHECKS)
+#define ENCIO_SKIPTO 0x10
+
+/* declarations to deal with WIN32 compile-flag-in-source-code crap */
+#if !defined(WIN32)
+#define XML2ENC_DECLARE(type) type
+#define XML2ENC_DECLARE_NONSTD(type) type
+#define XML2ENC_DECLARE_DATA
+#elif defined(XML2ENC_DECLARE_STATIC)
+#define XML2ENC_DECLARE(type) type __stdcall
+#define XML2ENC_DECLARE_NONSTD(type) type
+#define XML2ENC_DECLARE_DATA
+#elif defined(XML2ENC_DECLARE_EXPORT)
+#define XML2ENC_DECLARE(type) __declspec(dllexport) type __stdcall
+#define XML2ENC_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define XML2ENC_DECLARE_DATA __declspec(dllexport)
+#else
+#define XML2ENC_DECLARE(type) __declspec(dllimport) type __stdcall
+#define XML2ENC_DECLARE_NONSTD(type) __declspec(dllimport) type
+#define XML2ENC_DECLARE_DATA __declspec(dllimport)
+#endif
+
+APR_DECLARE_OPTIONAL_FN(apr_status_t, xml2enc_charset,
+ (request_rec* r, xmlCharEncoding* enc,
+ const char** cenc));
+
+APR_DECLARE_OPTIONAL_FN(apr_status_t, xml2enc_filter,
+ (request_rec* r, const char* enc, unsigned int mode));
+
+APR_DECLARE_EXTERNAL_HOOK(xml2enc, XML2ENC, int, preprocess,
+ (ap_filter_t *f, char** bufp, apr_size_t* bytesp))
+
+#endif
diff --git a/modules/filters/regexp.c b/modules/filters/regexp.c
new file mode 100644
index 00000000..ba118a65
--- /dev/null
+++ b/modules/filters/regexp.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ *
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ *
+ * 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.
+ */
+
+/* Code moved from regexp.h */
+
+#include "apr.h"
+#include "apr_lib.h"
+#ifdef APR_HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "libsed.h"
+#include "regexp.h"
+#include "sed.h"
+
+#define GETC() ((unsigned char)*sp++)
+#define PEEKC() ((unsigned char)*sp)
+#define UNGETC(c) (--sp)
+#define SEDCOMPILE_ERROR(c) { \
+ regerrno = c; \
+ goto out; \
+ }
+#define ecmp(s1, s2, n) (strncmp(s1, s2, n) == 0)
+#define uletter(c) (isalpha(c) || c == '_')
+
+
+static unsigned char bittab[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+static int regerr(sed_commands_t *commands, int err);
+static void comperr(sed_commands_t *commands, char *msg);
+static void getrnge(char *str, step_vars_storage *vars);
+static int _advance(char *, char *, step_vars_storage *);
+extern int sed_step(char *p1, char *p2, int circf, step_vars_storage *vars);
+
+
+static void comperr(sed_commands_t *commands, char *msg)
+{
+ command_errf(commands, msg, commands->linebuf);
+}
+
+/*
+*/
+static int regerr(sed_commands_t *commands, int err)
+{
+ switch(err) {
+ case 0:
+ /* No error */
+ break;
+ case 11:
+ comperr(commands, "Range endpoint too large: %s");
+ break;
+
+ case 16:
+ comperr(commands, "Bad number: %s");
+ break;
+
+ case 25:
+ comperr(commands, "``\\digit'' out of range: %s");
+ break;
+
+ case 36:
+ comperr(commands, "Illegal or missing delimiter: %s");
+ break;
+
+ case 41:
+ comperr(commands, "No remembered search string: %s");
+ break;
+
+ case 42:
+ comperr(commands, "\\( \\) imbalance: %s");
+ break;
+
+ case 43:
+ comperr(commands, "Too many \\(: %s");
+ break;
+
+ case 44:
+ comperr(commands, "More than 2 numbers given in \\{ \\}: %s");
+ break;
+
+ case 45:
+ comperr(commands, "} expected after \\: %s");
+ break;
+
+ case 46:
+ comperr(commands, "First number exceeds second in \\{ \\}: %s");
+ break;
+
+ case 49:
+ comperr(commands, "[ ] imbalance: %s");
+ break;
+
+ case 50:
+ comperr(commands, SEDERR_TMMES);
+ break;
+
+ default:
+ comperr(commands, "Unknown regexp error code %s\n");
+ break;
+ }
+ return (0);
+}
+
+
+char *sed_compile(sed_commands_t *commands, sed_comp_args *compargs,
+ char *ep, char *endbuf, int seof)
+{
+ int c;
+ int eof = seof;
+ char *lastep;
+ int cclcnt;
+ char bracket[NBRA], *bracketp;
+ int closed;
+ int neg;
+ int lc;
+ int i, cflg;
+ int iflag; /* used for non-ascii characters in brackets */
+ char *sp = commands->cp;
+ int regerrno = 0;
+
+ lastep = 0;
+ if ((c = GETC()) == eof || c == '\n') {
+ if (c == '\n') {
+ UNGETC(c);
+ }
+ commands->cp = sp;
+ goto out;
+ }
+ bracketp = bracket;
+ compargs->circf = closed = compargs->nbra = 0;
+ if (c == '^')
+ compargs->circf++;
+ else
+ UNGETC(c);
+ while (1) {
+ if (ep >= endbuf)
+ SEDCOMPILE_ERROR(50);
+ c = GETC();
+ if (c != '*' && ((c != '\\') || (PEEKC() != '{')))
+ lastep = ep;
+ if (c == eof) {
+ *ep++ = CCEOF;
+ if (bracketp != bracket)
+ SEDCOMPILE_ERROR(42);
+ commands->cp = sp;
+ goto out;
+ }
+ switch (c) {
+
+ case '.':
+ *ep++ = CDOT;
+ continue;
+
+ case '\n':
+ SEDCOMPILE_ERROR(36);
+ commands->cp = sp;
+ goto out;
+ case '*':
+ if (lastep == 0 || *lastep == CBRA || *lastep == CKET)
+ goto defchar;
+ *lastep |= STAR;
+ continue;
+
+ case '$':
+ if (PEEKC() != eof && PEEKC() != '\n')
+ goto defchar;
+ *ep++ = CDOL;
+ continue;
+
+ case '[':
+ if (&ep[17] >= endbuf)
+ SEDCOMPILE_ERROR(50);
+
+ *ep++ = CCL;
+ lc = 0;
+ for (i = 0; i < 16; i++)
+ ep[i] = 0;
+
+ neg = 0;
+ if ((c = GETC()) == '^') {
+ neg = 1;
+ c = GETC();
+ }
+ iflag = 1;
+ do {
+ c &= 0377;
+ if (c == '\0' || c == '\n')
+ SEDCOMPILE_ERROR(49);
+ if ((c & 0200) && iflag) {
+ iflag = 0;
+ if (&ep[32] >= endbuf)
+ SEDCOMPILE_ERROR(50);
+ ep[-1] = CXCL;
+ for (i = 16; i < 32; i++)
+ ep[i] = 0;
+ }
+ if (c == '-' && lc != 0) {
+ if ((c = GETC()) == ']') {
+ PLACE('-');
+ break;
+ }
+ if ((c & 0200) && iflag) {
+ iflag = 0;
+ if (&ep[32] >= endbuf)
+ SEDCOMPILE_ERROR(50);
+ ep[-1] = CXCL;
+ for (i = 16; i < 32; i++)
+ ep[i] = 0;
+ }
+ while (lc < c) {
+ PLACE(lc);
+ lc++;
+ }
+ }
+ lc = c;
+ PLACE(c);
+ } while ((c = GETC()) != ']');
+
+ if (iflag)
+ iflag = 16;
+ else
+ iflag = 32;
+
+ if (neg) {
+ if (iflag == 32) {
+ for (cclcnt = 0; cclcnt < iflag;
+ cclcnt++)
+ ep[cclcnt] ^= 0377;
+ ep[0] &= 0376;
+ } else {
+ ep[-1] = NCCL;
+ /* make nulls match so test fails */
+ ep[0] |= 01;
+ }
+ }
+
+ ep += iflag;
+
+ continue;
+
+ case '\\':
+ switch (c = GETC()) {
+
+ case '(':
+ if (compargs->nbra >= NBRA)
+ SEDCOMPILE_ERROR(43);
+ *bracketp++ = compargs->nbra;
+ *ep++ = CBRA;
+ *ep++ = compargs->nbra++;
+ continue;
+
+ case ')':
+ if (bracketp <= bracket)
+ SEDCOMPILE_ERROR(42);
+ *ep++ = CKET;
+ *ep++ = *--bracketp;
+ closed++;
+ continue;
+
+ case '{':
+ if (lastep == (char *) 0)
+ goto defchar;
+ *lastep |= RNGE;
+ cflg = 0;
+ nlim:
+ c = GETC();
+ i = 0;
+ do {
+ if ('0' <= c && c <= '9')
+ i = 10 * i + c - '0';
+ else
+ SEDCOMPILE_ERROR(16);
+ } while (((c = GETC()) != '\\') && (c != ','));
+ if (i >= 255)
+ SEDCOMPILE_ERROR(11);
+ *ep++ = i;
+ if (c == ',') {
+ if (cflg++)
+ SEDCOMPILE_ERROR(44);
+ if ((c = GETC()) == '\\')
+ *ep++ = (char) 255;
+ else {
+ UNGETC(c);
+ goto nlim;
+ /* get 2'nd number */
+ }
+ }
+ if (GETC() != '}')
+ SEDCOMPILE_ERROR(45);
+ if (!cflg) /* one number */
+ *ep++ = i;
+ else if ((ep[-1] & 0377) < (ep[-2] & 0377))
+ SEDCOMPILE_ERROR(46);
+ continue;
+
+ case '\n':
+ SEDCOMPILE_ERROR(36);
+
+ case 'n':
+ c = '\n';
+ goto defchar;
+
+ default:
+ if (c >= '1' && c <= '9') {
+ if ((c -= '1') >= closed)
+ SEDCOMPILE_ERROR(25);
+ *ep++ = CBACK;
+ *ep++ = c;
+ continue;
+ }
+ }
+ /* Drop through to default to use \ to turn off special chars */
+
+ defchar:
+ default:
+ lastep = ep;
+ *ep++ = CCHR;
+ *ep++ = c;
+ }
+ }
+out:
+ if (regerrno) {
+ regerr(commands, regerrno);
+ return (char*) NULL;
+ }
+ /* XXX : Basant : what extra */
+ /* int reglength = (int)(ep - expbuf); */
+ return ep;
+}
+
+int sed_step(char *p1, char *p2, int circf, step_vars_storage *vars)
+{
+ int c;
+
+
+ if (circf) {
+ vars->loc1 = p1;
+ return (_advance(p1, p2, vars));
+ }
+ /* fast check for first character */
+ if (*p2 == CCHR) {
+ c = p2[1];
+ do {
+ if (*p1 != c)
+ continue;
+ if (_advance(p1, p2, vars)) {
+ vars->loc1 = p1;
+ return (1);
+ }
+ } while (*p1++);
+ return (0);
+ }
+ /* regular algorithm */
+ do {
+ if (_advance(p1, p2, vars)) {
+ vars->loc1 = p1;
+ return (1);
+ }
+ } while (*p1++);
+ return (0);
+}
+
+static int _advance(char *lp, char *ep, step_vars_storage *vars)
+{
+ char *curlp;
+ int c;
+ char *bbeg;
+ char neg;
+ int ct;
+ int epint; /* int value of *ep */
+
+ while (1) {
+ neg = 0;
+ switch (*ep++) {
+
+ case CCHR:
+ if (*ep++ == *lp++)
+ continue;
+ return (0);
+
+ case CDOT:
+ if (*lp++)
+ continue;
+ return (0);
+
+ case CDOL:
+ if (*lp == 0)
+ continue;
+ return (0);
+
+ case CCEOF:
+ vars->loc2 = lp;
+ return (1);
+
+ case CXCL:
+ c = (unsigned char)*lp++;
+ if (ISTHERE(c)) {
+ ep += 32;
+ continue;
+ }
+ return (0);
+
+ case NCCL:
+ neg = 1;
+
+ case CCL:
+ c = *lp++;
+ if (((c & 0200) == 0 && ISTHERE(c)) ^ neg) {
+ ep += 16;
+ continue;
+ }
+ return (0);
+
+ case CBRA:
+ epint = (int) *ep;
+ vars->braslist[epint] = lp;
+ ep++;
+ continue;
+
+ case CKET:
+ epint = (int) *ep;
+ vars->braelist[epint] = lp;
+ ep++;
+ continue;
+
+ case CCHR | RNGE:
+ c = *ep++;
+ getrnge(ep, vars);
+ while (vars->low--)
+ if (*lp++ != c)
+ return (0);
+ curlp = lp;
+ while (vars->size--)
+ if (*lp++ != c)
+ break;
+ if (vars->size < 0)
+ lp++;
+ ep += 2;
+ goto star;
+
+ case CDOT | RNGE:
+ getrnge(ep, vars);
+ while (vars->low--)
+ if (*lp++ == '\0')
+ return (0);
+ curlp = lp;
+ while (vars->size--)
+ if (*lp++ == '\0')
+ break;
+ if (vars->size < 0)
+ lp++;
+ ep += 2;
+ goto star;
+
+ case CXCL | RNGE:
+ getrnge(ep + 32, vars);
+ while (vars->low--) {
+ c = (unsigned char)*lp++;
+ if (!ISTHERE(c))
+ return (0);
+ }
+ curlp = lp;
+ while (vars->size--) {
+ c = (unsigned char)*lp++;
+ if (!ISTHERE(c))
+ break;
+ }
+ if (vars->size < 0)
+ lp++;
+ ep += 34; /* 32 + 2 */
+ goto star;
+
+ case NCCL | RNGE:
+ neg = 1;
+
+ case CCL | RNGE:
+ getrnge(ep + 16, vars);
+ while (vars->low--) {
+ c = *lp++;
+ if (((c & 0200) || !ISTHERE(c)) ^ neg)
+ return (0);
+ }
+ curlp = lp;
+ while (vars->size--) {
+ c = *lp++;
+ if (((c & 0200) || !ISTHERE(c)) ^ neg)
+ break;
+ }
+ if (vars->size < 0)
+ lp++;
+ ep += 18; /* 16 + 2 */
+ goto star;
+
+ case CBACK:
+ epint = (int) *ep;
+ bbeg = vars->braslist[epint];
+ ct = vars->braelist[epint] - bbeg;
+ ep++;
+
+ if (ecmp(bbeg, lp, ct)) {
+ lp += ct;
+ continue;
+ }
+ return (0);
+
+ case CBACK | STAR:
+ epint = (int) *ep;
+ bbeg = vars->braslist[epint];
+ ct = vars->braelist[epint] - bbeg;
+ ep++;
+ curlp = lp;
+ while (ecmp(bbeg, lp, ct))
+ lp += ct;
+
+ while (lp >= curlp) {
+ if (_advance(lp, ep, vars))
+ return (1);
+ lp -= ct;
+ }
+ return (0);
+
+
+ case CDOT | STAR:
+ curlp = lp;
+ while (*lp++);
+ goto star;
+
+ case CCHR | STAR:
+ curlp = lp;
+ while (*lp++ == *ep);
+ ep++;
+ goto star;
+
+ case CXCL | STAR:
+ curlp = lp;
+ do {
+ c = (unsigned char)*lp++;
+ } while (ISTHERE(c));
+ ep += 32;
+ goto star;
+
+ case NCCL | STAR:
+ neg = 1;
+
+ case CCL | STAR:
+ curlp = lp;
+ do {
+ c = *lp++;
+ } while (((c & 0200) == 0 && ISTHERE(c)) ^ neg);
+ ep += 16;
+ goto star;
+
+ star:
+ do {
+ if (--lp == vars->locs)
+ break;
+ if (_advance(lp, ep, vars))
+ return (1);
+ } while (lp > curlp);
+ return (0);
+
+ }
+ }
+}
+
+static void getrnge(char *str, step_vars_storage *vars)
+{
+ vars->low = *str++ & 0377;
+ vars->size = ((*str & 0377) == 255)? 20000: (*str &0377) - vars->low;
+}
+
+
diff --git a/modules/filters/regexp.h b/modules/filters/regexp.h
new file mode 100644
index 00000000..1e5a6269
--- /dev/null
+++ b/modules/filters/regexp.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ *
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ *
+ * 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.
+ */
+
+#ifndef _REGEXP_H
+#define _REGEXP_H
+
+#include "libsed.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CBRA 2
+#define CCHR 4
+#define CDOT 8
+#define CCL 12
+#define CXCL 16
+#define CDOL 20
+#define CCEOF 22
+#define CKET 24
+#define CBACK 36
+#define NCCL 40
+
+#define STAR 01
+#define RNGE 03
+
+#define NBRA 9
+
+#define PLACE(c) ep[c >> 3] |= bittab[c & 07]
+#define ISTHERE(c) (ep[c >> 3] & bittab[c & 07])
+
+typedef struct _step_vars_storage {
+ char *loc1, *loc2, *locs;
+ char *braslist[NBRA];
+ char *braelist[NBRA];
+ int low;
+ int size;
+} step_vars_storage;
+
+typedef struct _sed_comp_args {
+ int circf; /* Regular expression starts with ^ */
+ int nbra; /* braces count */
+} sed_comp_args;
+
+extern char *sed_compile(sed_commands_t *commands, sed_comp_args *compargs,
+ char *ep, char *endbuf, int seof);
+extern void command_errf(sed_commands_t *commands, const char *fmt, ...);
+
+#define SEDERR_CGMES "command garbled: %s"
+#define SEDERR_SMMES "Space missing before filename: %s"
+#define SEDERR_TMMES "too much command text: %s"
+#define SEDERR_LTLMES "label too long: %s"
+#define SEDERR_ULMES "undefined label: %s"
+#define SEDERR_DLMES "duplicate labels: %s"
+#define SEDERR_TMLMES "too many labels: %s"
+#define SEDERR_AD0MES "no addresses allowed: %s"
+#define SEDERR_AD1MES "only one address allowed: %s"
+#define SEDERR_TOOBIG "suffix too large: %s"
+#define SEDERR_OOMMES "out of memory"
+#define SEDERR_COPFMES "cannot open pattern file: %s"
+#define SEDERR_COIFMES "cannot open input file: %s"
+#define SEDERR_TMOMES "too many {'s"
+#define SEDERR_TMCMES "too many }'s"
+#define SEDERR_NRMES "first RE may not be null"
+#define SEDERR_UCMES "unrecognized command: %s"
+#define SEDERR_TMWFMES "too many files in w commands"
+#define SEDERR_COMES "cannot open %s"
+#define SEDERR_CCMES "cannot create %s"
+#define SEDERR_TMLNMES "too many line numbers"
+#define SEDERR_TMAMES "too many appends after line %lld"
+#define SEDERR_TMRMES "too many reads after line %lld"
+#define SEDERR_DOORNG "``\\digit'' out of range: %s"
+#define SEDERR_EDMOSUB "ending delimiter missing on substitution: %s"
+#define SEDERR_EDMOSTR "ending delimiter missing on string: %s"
+#define SEDERR_FNTL "file name too long: %s"
+#define SEDERR_CLTL "command line too long"
+#define SEDERR_TSNTSS "transform strings not the same size: %s"
+#define SEDERR_OLTL "output line too long."
+#define SEDERR_HSOVERFLOW "hold space overflowed."
+#define SEDERR_INTERNAL "internal sed error"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REGEXP_H */
diff --git a/modules/filters/sed.h b/modules/filters/sed.h
new file mode 100644
index 00000000..cc3c03eb
--- /dev/null
+++ b/modules/filters/sed.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1984 AT&T
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _SED_H
+#define _SED_H
+
+#include <stdlib.h>
+#include <limits.h>
+
+#define CEND 16
+#define CLNUM 14
+
+#define RESIZE 10000
+#define LBSIZE 1000
+
+#define ACOM 01
+#define BCOM 020
+#define CCOM 02
+#define CDCOM 025
+#define CNCOM 022
+#define COCOM 017
+#define CPCOM 023
+#define DCOM 03
+#define ECOM 015
+#define EQCOM 013
+#define FCOM 016
+#define GCOM 027
+#define CGCOM 030
+#define HCOM 031
+#define CHCOM 032
+#define ICOM 04
+#define LCOM 05
+#define NCOM 012
+#define PCOM 010
+#define QCOM 011
+#define RCOM 06
+#define SCOM 07
+#define TCOM 021
+#define WCOM 014
+#define CWCOM 024
+#define YCOM 026
+#define XCOM 033
+
+#endif /* _SED_H */
diff --git a/modules/filters/sed0.c b/modules/filters/sed0.c
new file mode 100644
index 00000000..da47122a
--- /dev/null
+++ b/modules/filters/sed0.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1984 AT&T
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "libsed.h"
+#include "sed.h"
+#include "regexp.h"
+
+#define CCEOF 22
+
+static int fcomp(sed_commands_t *commands, apr_file_t *fin);
+static char *compsub(sed_commands_t *commands,
+ sed_comp_args *compargs, char *rhsbuf);
+static int rline(sed_commands_t *commands, apr_file_t *fin,
+ char *lbuf, char *lbend);
+static char *address(sed_commands_t *commands, char *expbuf,
+ apr_status_t* status);
+static char *text(sed_commands_t *commands, char *textbuf, char *endbuf);
+static sed_label_t *search(sed_commands_t *commands);
+static char *ycomp(sed_commands_t *commands, char *expbuf);
+static char *comple(sed_commands_t *commands, sed_comp_args *compargs,
+ char *x1, char *ep, char *x3, char x4);
+static sed_reptr_t *alloc_reptr(sed_commands_t *commands);
+static int check_finalized(const sed_commands_t *commands);
+
+void command_errf(sed_commands_t *commands, const char *fmt, ...)
+{
+ if (commands->errfn && commands->pool) {
+ va_list args;
+ const char* error;
+ va_start(args, fmt);
+ error = apr_pvsprintf(commands->pool, fmt, args);
+ commands->errfn(commands->data, error);
+ va_end(args);
+ }
+}
+
+/*
+ * sed_init_commands
+ */
+apr_status_t sed_init_commands(sed_commands_t *commands, sed_err_fn_t *errfn, void *data,
+ apr_pool_t *p)
+{
+ memset(commands, 0, sizeof(*commands));
+
+ commands->errfn = errfn;
+ commands->data = data;
+
+ commands->labtab = commands->ltab;
+ commands->lab = commands->labtab + 1;
+ commands->pool = p;
+
+ commands->respace = apr_pcalloc(p, RESIZE);
+ if (commands->respace == NULL) {
+ command_errf(commands, SEDERR_OOMMES);
+ return APR_EGENERAL;
+ }
+
+ commands->rep = alloc_reptr(commands);
+ if (commands->rep == NULL)
+ return APR_EGENERAL;
+
+ commands->rep->ad1 = commands->respace;
+ commands->reend = &commands->respace[RESIZE - 1];
+ commands->labend = &commands->labtab[SED_LABSIZE];
+ commands->canbefinal = 1;
+
+ return APR_SUCCESS;
+}
+
+/*
+ * sed_destroy_commands
+ */
+void sed_destroy_commands(sed_commands_t *commands)
+{
+}
+
+/*
+ * sed_compile_string
+ */
+apr_status_t sed_compile_string(sed_commands_t *commands, const char *s)
+{
+ apr_status_t rv;
+
+ commands->earg = s;
+ commands->eflag = 1;
+
+ rv = fcomp(commands, NULL);
+ if (rv == APR_SUCCESS)
+ commands->canbefinal = check_finalized(commands);
+
+ commands->eflag = 0;
+
+ return (rv != 0 ? APR_EGENERAL : APR_SUCCESS);
+}
+
+/*
+ * sed_compile_file
+ */
+apr_status_t sed_compile_file(sed_commands_t *commands, apr_file_t *fin)
+{
+ apr_status_t rv = fcomp(commands, fin);
+ return (rv != 0 ? APR_EGENERAL : APR_SUCCESS);
+}
+
+/*
+ * sed_get_finalize_error
+ */
+char* sed_get_finalize_error(const sed_commands_t *commands, apr_pool_t* pool)
+{
+ const sed_label_t *lab;
+ if (commands->depth) {
+ return SEDERR_TMOMES;
+ }
+
+ /* Empty branch chain is not a issue */
+ for (lab = commands->labtab + 1; lab < commands->lab; lab++) {
+ char *error;
+ if (lab->address == 0) {
+ error = apr_psprintf(pool, SEDERR_ULMES, lab->asc);
+ return error;
+ }
+
+ if (lab->chain) {
+ return SEDERR_INTERNAL;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * sed_canbe_finalized
+ */
+int sed_canbe_finalized(const sed_commands_t *commands)
+{
+ return commands->canbefinal;
+}
+
+/*
+ * check_finalized
+ */
+static int check_finalized(const sed_commands_t *commands)
+{
+ const sed_label_t *lab;
+ if (commands->depth) {
+ return 0;
+ }
+
+ /* Empty branch chain is not a issue */
+ for (lab = commands->labtab + 1; lab < commands->lab; lab++) {
+ if (lab->address == 0 || (lab->chain)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * dechain
+ */
+static void dechain(sed_label_t *lpt, sed_reptr_t *address)
+{
+ sed_reptr_t *rep;
+ if ((lpt == NULL) || (lpt->chain == NULL) || (address == NULL))
+ return;
+ rep = lpt->chain;
+ while (rep->lb1) {
+ sed_reptr_t *next;
+
+ next = rep->lb1;
+ rep->lb1 = address;
+ rep = next;
+ }
+ rep->lb1 = address;
+ lpt->chain = NULL;
+}
+
+/*
+ * fcomp
+ */
+static int fcomp(sed_commands_t *commands, apr_file_t *fin)
+{
+ char *p, *op, *tp;
+ sed_reptr_t *pt, *pt1;
+ int i, ii;
+ sed_label_t *lpt;
+ char fnamebuf[APR_PATH_MAX];
+ apr_status_t status;
+ sed_comp_args compargs;
+
+ op = commands->lastre;
+ if (!commands->linebuf) {
+ commands->linebuf = apr_pcalloc(commands->pool, LBSIZE + 1);
+ }
+
+ if (rline(commands, fin, commands->linebuf,
+ (commands->linebuf + LBSIZE + 1)) < 0)
+ return 0;
+ if (*commands->linebuf == '#') {
+ if (commands->linebuf[1] == 'n')
+ commands->nflag = 1;
+ }
+ else {
+ commands->cp = commands->linebuf;
+ goto comploop;
+ }
+
+ for (;;) {
+ if (rline(commands, fin, commands->linebuf,
+ (commands->linebuf + LBSIZE + 1)) < 0)
+ break;
+
+ commands->cp = commands->linebuf;
+
+comploop:
+ while (*commands->cp == ' ' || *commands->cp == '\t')
+ commands->cp++;
+ if (*commands->cp == '\0' || *commands->cp == '#')
+ continue;
+ if (*commands->cp == ';') {
+ commands->cp++;
+ goto comploop;
+ }
+
+ p = address(commands, commands->rep->ad1, &status);
+ if (status != APR_SUCCESS) {
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+
+ if (p == commands->rep->ad1) {
+ if (op)
+ commands->rep->ad1 = op;
+ else {
+ command_errf(commands, SEDERR_NRMES);
+ return -1;
+ }
+ } else if (p == 0) {
+ p = commands->rep->ad1;
+ commands->rep->ad1 = 0;
+ } else {
+ op = commands->rep->ad1;
+ if (*commands->cp == ',' || *commands->cp == ';') {
+ commands->cp++;
+ commands->rep->ad2 = p;
+ p = address(commands, commands->rep->ad2, &status);
+ if ((status != APR_SUCCESS) || (p == 0)) {
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+ if (p == commands->rep->ad2)
+ commands->rep->ad2 = op;
+ else
+ op = commands->rep->ad2;
+ } else
+ commands->rep->ad2 = 0;
+ }
+
+ if(p > &commands->respace[RESIZE-1]) {
+ command_errf(commands, SEDERR_TMMES);
+ return -1;
+ }
+
+ while (*commands->cp == ' ' || *commands->cp == '\t')
+ commands->cp++;
+
+swit:
+ switch(*commands->cp++) {
+ default:
+ command_errf(commands, SEDERR_UCMES, commands->linebuf);
+ return -1;
+
+ case '!':
+ commands->rep->negfl = 1;
+ goto swit;
+
+ case '{':
+ commands->rep->command = BCOM;
+ commands->rep->negfl = !(commands->rep->negfl);
+ commands->cmpend[commands->depth++] = &commands->rep->lb1;
+ commands->rep = alloc_reptr(commands);
+ commands->rep->ad1 = p;
+ if (*commands->cp == '\0')
+ continue;
+ goto comploop;
+
+ case '}':
+ if (commands->rep->ad1) {
+ command_errf(commands, SEDERR_AD0MES, commands->linebuf);
+ return -1;
+ }
+
+ if (--commands->depth < 0) {
+ command_errf(commands, SEDERR_TMCMES);
+ return -1;
+ }
+ *commands->cmpend[commands->depth] = commands->rep;
+
+ commands->rep->ad1 = p;
+ continue;
+
+ case '=':
+ commands->rep->command = EQCOM;
+ if (commands->rep->ad2) {
+ command_errf(commands, SEDERR_AD1MES, commands->linebuf);
+ return -1;
+ }
+ break;
+
+ case ':':
+ if (commands->rep->ad1) {
+ command_errf(commands, SEDERR_AD0MES, commands->linebuf);
+ return -1;
+ }
+
+ while (*commands->cp++ == ' ');
+ commands->cp--;
+
+ tp = commands->lab->asc;
+ while ((*tp++ = *commands->cp++)) {
+ if (tp >= &(commands->lab->asc[8])) {
+ command_errf(commands, SEDERR_LTLMES, commands->linebuf);
+ return -1;
+ }
+ }
+ *--tp = '\0';
+
+ if ((lpt = search(commands)) != NULL) {
+ if (lpt->address) {
+ command_errf(commands, SEDERR_DLMES, commands->linebuf);
+ return -1;
+ }
+ dechain(lpt, commands->rep);
+ } else {
+ commands->lab->chain = 0;
+ lpt = commands->lab;
+ if (++commands->lab >= commands->labend) {
+ command_errf(commands, SEDERR_TMLMES, commands->linebuf);
+ return -1;
+ }
+ }
+ lpt->address = commands->rep;
+ commands->rep->ad1 = p;
+
+ continue;
+
+ case 'a':
+ commands->rep->command = ACOM;
+ if (commands->rep->ad2) {
+ command_errf(commands, SEDERR_AD1MES, commands->linebuf);
+ return -1;
+ }
+ if (*commands->cp == '\\')
+ commands->cp++;
+ if (*commands->cp++ != '\n') {
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+ commands->rep->re1 = p;
+ p = text(commands, commands->rep->re1, commands->reend);
+ if (p == NULL)
+ return -1;
+ break;
+
+ case 'c':
+ commands->rep->command = CCOM;
+ if (*commands->cp == '\\') commands->cp++;
+ if (*commands->cp++ != ('\n')) {
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+ commands->rep->re1 = p;
+ p = text(commands, commands->rep->re1, commands->reend);
+ if (p == NULL)
+ return -1;
+ break;
+
+ case 'i':
+ commands->rep->command = ICOM;
+ if (commands->rep->ad2) {
+ command_errf(commands, SEDERR_AD1MES, commands->linebuf);
+ return -1;
+ }
+ if (*commands->cp == '\\') commands->cp++;
+ if (*commands->cp++ != ('\n')) {
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+ commands->rep->re1 = p;
+ p = text(commands, commands->rep->re1, commands->reend);
+ if (p == NULL)
+ return -1;
+ break;
+
+ case 'g':
+ commands->rep->command = GCOM;
+ break;
+
+ case 'G':
+ commands->rep->command = CGCOM;
+ break;
+
+ case 'h':
+ commands->rep->command = HCOM;
+ break;
+
+ case 'H':
+ commands->rep->command = CHCOM;
+ break;
+
+ case 't':
+ commands->rep->command = TCOM;
+ goto jtcommon;
+
+ case 'b':
+ commands->rep->command = BCOM;
+jtcommon:
+ while (*commands->cp++ == ' ');
+ commands->cp--;
+
+ if (*commands->cp == '\0') {
+ if ((pt = commands->labtab->chain) != NULL) {
+ while ((pt1 = pt->lb1) != NULL)
+ pt = pt1;
+ pt->lb1 = commands->rep;
+ } else
+ commands->labtab->chain = commands->rep;
+ break;
+ }
+ tp = commands->lab->asc;
+ while ((*tp++ = *commands->cp++))
+ if (tp >= &(commands->lab->asc[8])) {
+ command_errf(commands, SEDERR_LTLMES, commands->linebuf);
+ return -1;
+ }
+ commands->cp--;
+ *--tp = '\0';
+
+ if ((lpt = search(commands)) != NULL) {
+ if (lpt->address) {
+ commands->rep->lb1 = lpt->address;
+ } else {
+ pt = lpt->chain;
+ while ((pt1 = pt->lb1) != NULL)
+ pt = pt1;
+ pt->lb1 = commands->rep;
+ }
+ } else {
+ commands->lab->chain = commands->rep;
+ commands->lab->address = 0;
+ if (++commands->lab >= commands->labend) {
+ command_errf(commands, SEDERR_TMLMES, commands->linebuf);
+ return -1;
+ }
+ }
+ break;
+
+ case 'n':
+ commands->rep->command = NCOM;
+ break;
+
+ case 'N':
+ commands->rep->command = CNCOM;
+ break;
+
+ case 'p':
+ commands->rep->command = PCOM;
+ break;
+
+ case 'P':
+ commands->rep->command = CPCOM;
+ break;
+
+ case 'r':
+ commands->rep->command = RCOM;
+ if (commands->rep->ad2) {
+ command_errf(commands, SEDERR_AD1MES, commands->linebuf);
+ return -1;
+ }
+ if (*commands->cp++ != ' ') {
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+ commands->rep->re1 = p;
+ p = text(commands, commands->rep->re1, commands->reend);
+ if (p == NULL)
+ return -1;
+ break;
+
+ case 'd':
+ commands->rep->command = DCOM;
+ break;
+
+ case 'D':
+ commands->rep->command = CDCOM;
+ commands->rep->lb1 = commands->ptrspace;
+ break;
+
+ case 'q':
+ commands->rep->command = QCOM;
+ if (commands->rep->ad2) {
+ command_errf(commands, SEDERR_AD1MES, commands->linebuf);
+ return -1;
+ }
+ break;
+
+ case 'l':
+ commands->rep->command = LCOM;
+ break;
+
+ case 's':
+ commands->rep->command = SCOM;
+ commands->sseof = *commands->cp++;
+ commands->rep->re1 = p;
+ p = comple(commands, &compargs, (char *) 0, commands->rep->re1,
+ commands->reend, commands->sseof);
+ if (p == NULL)
+ return -1;
+ if (p == commands->rep->re1) {
+ if (op)
+ commands->rep->re1 = op;
+ else {
+ command_errf(commands, SEDERR_NRMES);
+ return -1;
+ }
+ } else
+ op = commands->rep->re1;
+ commands->rep->rhs = p;
+
+ p = compsub(commands, &compargs, commands->rep->rhs);
+ if ((p) == NULL)
+ return -1;
+
+ if (*commands->cp == 'g') {
+ commands->cp++;
+ commands->rep->gfl = 999;
+ } else if (commands->gflag)
+ commands->rep->gfl = 999;
+
+ if (*commands->cp >= '1' && *commands->cp <= '9') {
+ i = *commands->cp - '0';
+ commands->cp++;
+ while (1) {
+ ii = *commands->cp;
+ if (ii < '0' || ii > '9')
+ break;
+ i = i*10 + ii - '0';
+ if (i > 512) {
+ command_errf(commands, SEDERR_TOOBIG, commands->linebuf);
+ return -1;
+ }
+ commands->cp++;
+ }
+ commands->rep->gfl = i;
+ }
+
+ if (*commands->cp == 'p') {
+ commands->cp++;
+ commands->rep->pfl = 1;
+ }
+
+ if (*commands->cp == 'P') {
+ commands->cp++;
+ commands->rep->pfl = 2;
+ }
+
+ if (*commands->cp == 'w') {
+ commands->cp++;
+ if (*commands->cp++ != ' ') {
+ command_errf(commands, SEDERR_SMMES, commands->linebuf);
+ return -1;
+ }
+ if (text(commands, fnamebuf, &fnamebuf[APR_PATH_MAX]) == NULL) {
+ command_errf(commands, SEDERR_FNTL, commands->linebuf);
+ return -1;
+ }
+ for (i = commands->nfiles - 1; i >= 0; i--)
+ if (strcmp(fnamebuf,commands->fname[i]) == 0) {
+ commands->rep->findex = i;
+ goto done;
+ }
+ if (commands->nfiles >= NWFILES) {
+ command_errf(commands, SEDERR_TMWFMES);
+ return -1;
+ }
+ commands->fname[commands->nfiles] =
+ apr_pstrdup(commands->pool, fnamebuf);
+ if (commands->fname[commands->nfiles] == NULL) {
+ command_errf(commands, SEDERR_OOMMES);
+ return -1;
+ }
+ commands->rep->findex = commands->nfiles++;
+ }
+ break;
+
+ case 'w':
+ commands->rep->command = WCOM;
+ if (*commands->cp++ != ' ') {
+ command_errf(commands, SEDERR_SMMES, commands->linebuf);
+ return -1;
+ }
+ if (text(commands, fnamebuf, &fnamebuf[APR_PATH_MAX]) == NULL) {
+ command_errf(commands, SEDERR_FNTL, commands->linebuf);
+ return -1;
+ }
+ for (i = commands->nfiles - 1; i >= 0; i--)
+ if (strcmp(fnamebuf, commands->fname[i]) == 0) {
+ commands->rep->findex = i;
+ goto done;
+ }
+ if (commands->nfiles >= NWFILES) {
+ command_errf(commands, SEDERR_TMWFMES);
+ return -1;
+ }
+ if ((commands->fname[commands->nfiles] =
+ apr_pstrdup(commands->pool, fnamebuf)) == NULL) {
+ command_errf(commands, SEDERR_OOMMES);
+ return -1;
+ }
+
+ commands->rep->findex = commands->nfiles++;
+ break;
+
+ case 'x':
+ commands->rep->command = XCOM;
+ break;
+
+ case 'y':
+ commands->rep->command = YCOM;
+ commands->sseof = *commands->cp++;
+ commands->rep->re1 = p;
+ p = ycomp(commands, commands->rep->re1);
+ if (p == NULL)
+ return -1;
+ break;
+ }
+done:
+ commands->rep = alloc_reptr(commands);
+
+ commands->rep->ad1 = p;
+
+ if (*commands->cp++ != '\0') {
+ if (commands->cp[-1] == ';')
+ goto comploop;
+ command_errf(commands, SEDERR_CGMES, commands->linebuf);
+ return -1;
+ }
+ }
+ commands->rep->command = 0;
+ commands->lastre = op;
+
+ return 0;
+}
+
+static char *compsub(sed_commands_t *commands,
+ sed_comp_args *compargs, char *rhsbuf)
+{
+ char *p, *q;
+
+ p = rhsbuf;
+ q = commands->cp;
+ for(;;) {
+ if(p > &commands->respace[RESIZE-1]) {
+ command_errf(commands, SEDERR_TMMES, commands->linebuf);
+ return NULL;
+ }
+ if((*p = *q++) == '\\') {
+ p++;
+ if(p > &commands->respace[RESIZE-1]) {
+ command_errf(commands, SEDERR_TMMES, commands->linebuf);
+ return NULL;
+ }
+ *p = *q++;
+ if(*p > compargs->nbra + '0' && *p <= '9') {
+ command_errf(commands, SEDERR_DOORNG, commands->linebuf);
+ return NULL;
+ }
+ p++;
+ continue;
+ }
+ if(*p == commands->sseof) {
+ *p++ = '\0';
+ commands->cp = q;
+ return(p);
+ }
+ if(*p++ == '\0') {
+ command_errf(commands, SEDERR_EDMOSUB, commands->linebuf);
+ return NULL;
+ }
+ }
+}
+
+/*
+ * rline
+ */
+static int rline(sed_commands_t *commands, apr_file_t *fin,
+ char *lbuf, char *lbend)
+{
+ char *p;
+ const char *q;
+ int t;
+ apr_size_t bytes_read;
+
+ p = lbuf;
+
+ if(commands->eflag) {
+ if(commands->eflag > 0) {
+ commands->eflag = -1;
+ q = commands->earg;
+ while((t = *q++) != '\0') {
+ if(t == '\n') {
+ commands->saveq = q;
+ goto out1;
+ }
+ if (p < lbend)
+ *p++ = t;
+ if(t == '\\') {
+ if((t = *q++) == '\0') {
+ commands->saveq = NULL;
+ return(-1);
+ }
+ if (p < lbend)
+ *p++ = t;
+ }
+ }
+ commands->saveq = NULL;
+
+ out1:
+ if (p == lbend) {
+ command_errf(commands, SEDERR_CLTL, commands->linebuf);
+ return -1;
+ }
+ *p = '\0';
+ return(1);
+ }
+ if((q = commands->saveq) == 0) return(-1);
+
+ while((t = *q++) != '\0') {
+ if(t == '\n') {
+ commands->saveq = q;
+ goto out2;
+ }
+ if(p < lbend)
+ *p++ = t;
+ if(t == '\\') {
+ if((t = *q++) == '\0') {
+ commands->saveq = NULL;
+ return(-1);
+ }
+ if (p < lbend)
+ *p++ = t;
+ }
+ }
+ commands->saveq = NULL;
+
+ out2:
+ if (p == lbend) {
+ command_errf(commands, SEDERR_CLTL, commands->linebuf);
+ return -1;
+ }
+ *p = '\0';
+ return(1);
+ }
+
+ bytes_read = 1;
+ /* XXX extremely inefficient 1 byte reads */
+ while (apr_file_read(fin, &t, &bytes_read) != APR_SUCCESS) {
+ if(t == '\n') {
+ if (p == lbend) {
+ command_errf(commands, SEDERR_CLTL, commands->linebuf);
+ return -1;
+ }
+ *p = '\0';
+ return(1);
+ }
+ if (p < lbend)
+ *p++ = t;
+ if(t == '\\') {
+ bytes_read = 1;
+ if (apr_file_read(fin, &t, &bytes_read) != APR_SUCCESS) {
+ return -1;
+ }
+ if(p < lbend)
+ *p++ = t;
+ }
+ bytes_read = 1;
+ }
+ return(-1);
+}
+
+/*
+ * address
+ */
+static char *address(sed_commands_t *commands, char *expbuf,
+ apr_status_t* status)
+{
+ char *rcp;
+ apr_int64_t lno;
+ sed_comp_args compargs;
+
+ *status = APR_SUCCESS;
+ if(*commands->cp == '$') {
+ if (expbuf > &commands->respace[RESIZE-2]) {
+ command_errf(commands, SEDERR_TMMES, commands->linebuf);
+ *status = APR_EGENERAL;
+ return NULL;
+ }
+ commands->cp++;
+ *expbuf++ = CEND;
+ *expbuf++ = CCEOF;
+ return(expbuf);
+ }
+ if (*commands->cp == '/' || *commands->cp == '\\' ) {
+ if ( *commands->cp == '\\' )
+ commands->cp++;
+ commands->sseof = *commands->cp++;
+ return(comple(commands, &compargs, (char *) 0, expbuf, commands->reend,
+ commands->sseof));
+ }
+
+ rcp = commands->cp;
+ lno = 0;
+
+ while(*rcp >= '0' && *rcp <= '9')
+ lno = lno*10 + *rcp++ - '0';
+
+ if(rcp > commands->cp) {
+ if (expbuf > &commands->respace[RESIZE-3]) {
+ command_errf(commands, SEDERR_TMMES, commands->linebuf);
+ *status = APR_EGENERAL;
+ return NULL;
+ }
+ *expbuf++ = CLNUM;
+ *expbuf++ = commands->nlno;
+ commands->tlno[commands->nlno++] = lno;
+ if(commands->nlno >= SED_NLINES) {
+ command_errf(commands, SEDERR_TMLNMES, commands->linebuf);
+ *status = APR_EGENERAL;
+ return NULL;
+ }
+ *expbuf++ = CCEOF;
+ commands->cp = rcp;
+ return(expbuf);
+ }
+ return(NULL);
+}
+
+/*
+ * text
+ */
+static char *text(sed_commands_t *commands, char *textbuf, char *tbend)
+{
+ char *p, *q;
+
+ p = textbuf;
+ q = commands->cp;
+#ifndef S5EMUL
+ /*
+ * Strip off indentation from text to be inserted.
+ */
+ while(*q == '\t' || *q == ' ') q++;
+#endif
+ for(;;) {
+
+ if(p > tbend)
+ return(NULL); /* overflowed the buffer */
+ if((*p = *q++) == '\\')
+ *p = *q++;
+ if(*p == '\0') {
+ commands->cp = --q;
+ return(++p);
+ }
+#ifndef S5EMUL
+ /*
+ * Strip off indentation from text to be inserted.
+ */
+ if(*p == '\n') {
+ while(*q == '\t' || *q == ' ') q++;
+ }
+#endif
+ p++;
+ }
+}
+
+
+/*
+ * search
+ */
+static sed_label_t *search(sed_commands_t *commands)
+{
+ sed_label_t *rp;
+ sed_label_t *ptr;
+
+ rp = commands->labtab;
+ ptr = commands->lab;
+ while (rp < ptr) {
+ if (strcmp(rp->asc, ptr->asc) == 0)
+ return rp;
+ rp++;
+ }
+
+ return 0;
+}
+
+/*
+ * ycomp
+ */
+static char *ycomp(sed_commands_t *commands, char *expbuf)
+{
+ char c;
+ int cint; /* integer value of char c */
+ char *ep, *tsp;
+ int i;
+ char *sp;
+
+ ep = expbuf;
+ if(ep + 0377 > &commands->respace[RESIZE-1]) {
+ command_errf(commands, SEDERR_TMMES, commands->linebuf);
+ return NULL;
+ }
+ sp = commands->cp;
+ for(tsp = commands->cp; (c = *tsp) != commands->sseof; tsp++) {
+ if(c == '\\')
+ tsp++;
+ if(c == '\0' || c == '\n') {
+ command_errf(commands, SEDERR_EDMOSTR, commands->linebuf);
+ return NULL;
+ }
+ }
+ tsp++;
+ memset(ep, 0, 0400);
+
+ while((c = *sp++) != commands->sseof) {
+ c &= 0377;
+ if(c == '\\' && *sp == 'n') {
+ sp++;
+ c = '\n';
+ }
+ cint = (int) c;
+ if((ep[cint] = *tsp++) == '\\' && *tsp == 'n') {
+ ep[cint] = '\n';
+ tsp++;
+ }
+ if(ep[cint] == commands->sseof || ep[cint] == '\0') {
+ command_errf(commands, SEDERR_TSNTSS, commands->linebuf);
+ }
+ }
+ if(*tsp != commands->sseof) {
+ if(*tsp == '\0') {
+ command_errf(commands, SEDERR_EDMOSTR, commands->linebuf);
+ }
+ else {
+ command_errf(commands, SEDERR_TSNTSS, commands->linebuf);
+ }
+ return NULL;
+ }
+ commands->cp = ++tsp;
+
+ for(i = 0; i < 0400; i++)
+ if(ep[i] == 0)
+ ep[i] = i;
+
+ return(ep + 0400);
+}
+
+/*
+ * comple
+ */
+static char *comple(sed_commands_t *commands, sed_comp_args *compargs,
+ char *x1, char *ep, char *x3, char x4)
+{
+ char *p;
+
+ p = sed_compile(commands, compargs, ep + 1, x3, x4);
+ if(p == ep + 1)
+ return(ep);
+ *ep = compargs->circf;
+ return(p);
+}
+
+/*
+ * alloc_reptr
+ */
+static sed_reptr_t *alloc_reptr(sed_commands_t *commands)
+{
+ sed_reptr_t *var;
+
+ var = apr_pcalloc(commands->pool, sizeof(sed_reptr_t));
+ if (var == NULL) {
+ command_errf(commands, SEDERR_OOMMES);
+ return 0;
+ }
+
+ var->nrep = commands->nrep;
+ var->findex = -1;
+ commands->nrep++;
+
+ if (commands->ptrspace == NULL)
+ commands->ptrspace = var;
+ else
+ commands->ptrend->next = var;
+
+ commands->ptrend = var;
+ commands->labtab->address = var;
+ return var;
+}
+
+
diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c
new file mode 100644
index 00000000..ddca3bdb
--- /dev/null
+++ b/modules/filters/sed1.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1984 AT&T
+ * All Rights Reserved
+ *
+ * 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.
+ */
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "libsed.h"
+#include "sed.h"
+#include "apr_strings.h"
+#include "regexp.h"
+
+char *trans[040] = {
+ "\\01",
+ "\\02",
+ "\\03",
+ "\\04",
+ "\\05",
+ "\\06",
+ "\\07",
+ "\\10",
+ "\\11",
+ "\n",
+ "\\13",
+ "\\14",
+ "\\15",
+ "\\16",
+ "\\17",
+ "\\20",
+ "\\21",
+ "\\22",
+ "\\23",
+ "\\24",
+ "\\25",
+ "\\26",
+ "\\27",
+ "\\30",
+ "\\31",
+ "\\32",
+ "\\33",
+ "\\34",
+ "\\35",
+ "\\36",
+ "\\37"
+};
+char rub[] = {"\\177"};
+
+extern int sed_step(char *p1, char *p2, int circf, step_vars_storage *vars);
+static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
+ step_vars_storage *step_vars);
+static apr_status_t execute(sed_eval_t *eval);
+static int match(sed_eval_t *eval, char *expbuf, int gf,
+ step_vars_storage *step_vars);
+static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
+ step_vars_storage *step_vars);
+static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
+static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
+ step_vars_storage *step_vars);
+static apr_status_t wline(sed_eval_t *eval, char *buf, int sz);
+static apr_status_t arout(sed_eval_t *eval);
+
+static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
+{
+ if (eval->errfn && eval->pool) {
+ va_list args;
+ const char* error;
+ va_start(args, fmt);
+ error = apr_pvsprintf(eval->pool, fmt, args);
+ eval->errfn(eval->data, error);
+ va_end(args);
+ }
+}
+
+#define INIT_BUF_SIZE 1024
+
+/*
+ * grow_buffer
+ */
+static void grow_buffer(apr_pool_t *pool, char **buffer,
+ char **spend, unsigned int *cursize,
+ unsigned int newsize)
+{
+ char* newbuffer = NULL;
+ int spendsize = 0;
+ if (*cursize >= newsize)
+ return;
+ /* Avoid number of times realloc is called. It could cause huge memory
+ * requirement if line size is huge e.g 2 MB */
+ if (newsize < *cursize * 2) {
+ newsize = *cursize * 2;
+ }
+
+ /* Align it to 4 KB boundary */
+ newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) -1);
+ newbuffer = apr_pcalloc(pool, newsize);
+ if (*spend && *buffer && (*cursize > 0)) {
+ spendsize = *spend - *buffer;
+ }
+ if ((*cursize > 0) && *buffer) {
+ memcpy(newbuffer, *buffer, *cursize);
+ }
+ *buffer = newbuffer;
+ *cursize = newsize;
+ if (spend != buffer) {
+ *spend = *buffer + spendsize;
+ }
+}
+
+/*
+ * grow_line_buffer
+ */
+static void grow_line_buffer(sed_eval_t *eval, int newsize)
+{
+ grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
+ &eval->lsize, newsize);
+}
+
+/*
+ * grow_hold_buffer
+ */
+static void grow_hold_buffer(sed_eval_t *eval, int newsize)
+{
+ grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
+ &eval->hsize, newsize);
+}
+
+/*
+ * grow_gen_buffer
+ */
+static void grow_gen_buffer(sed_eval_t *eval, int newsize,
+ char **gspend)
+{
+ if (gspend == NULL) {
+ gspend = &eval->genbuf;
+ }
+ grow_buffer(eval->pool, &eval->genbuf, gspend,
+ &eval->gsize, newsize);
+ eval->lcomend = &eval->genbuf[71];
+}
+
+/*
+ * appendmem_to_linebuf
+ */
+static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
+{
+ unsigned int reqsize = (eval->lspend - eval->linebuf) + len;
+ if (eval->lsize < reqsize) {
+ grow_line_buffer(eval, reqsize);
+ }
+ memcpy(eval->lspend, sz, len);
+ eval->lspend += len;
+}
+
+/*
+ * append_to_linebuf
+ */
+static void append_to_linebuf(sed_eval_t *eval, const char* sz)
+{
+ int len = strlen(sz);
+ /* Copy string including null character */
+ appendmem_to_linebuf(eval, sz, len + 1);
+ --eval->lspend; /* lspend will now point to NULL character */
+}
+
+/*
+ * copy_to_linebuf
+ */
+static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
+{
+ eval->lspend = eval->linebuf;
+ append_to_linebuf(eval, sz);
+}
+
+/*
+ * append_to_holdbuf
+ */
+static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
+{
+ int len = strlen(sz);
+ unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1;
+ if (eval->hsize <= reqsize) {
+ grow_hold_buffer(eval, reqsize);
+ }
+ strcpy(eval->hspend, sz);
+ /* hspend will now point to NULL character */
+ eval->hspend += len;
+}
+
+/*
+ * copy_to_holdbuf
+ */
+static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
+{
+ eval->hspend = eval->holdbuf;
+ append_to_holdbuf(eval, sz);
+}
+
+/*
+ * append_to_genbuf
+ */
+static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
+{
+ int len = strlen(sz);
+ unsigned int reqsize = (*gspend - eval->genbuf) + len + 1;
+ if (eval->gsize < reqsize) {
+ grow_gen_buffer(eval, reqsize, gspend);
+ }
+ strcpy(*gspend, sz);
+ /* *gspend will now point to NULL character */
+ *gspend += len;
+}
+
+/*
+ * copy_to_genbuf
+ */
+static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
+{
+ int len = strlen(sz);
+ unsigned int reqsize = len + 1;
+ if (eval->gsize < reqsize) {
+ grow_gen_buffer(eval, reqsize, NULL);
+ }
+}
+
+/*
+ * sed_init_eval
+ */
+apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data, sed_write_fn_t *writefn, apr_pool_t* p)
+{
+ memset(eval, 0, sizeof(*eval));
+ eval->pool = p;
+ eval->writefn = writefn;
+ return sed_reset_eval(eval, commands, errfn, data);
+}
+
+/*
+ * sed_reset_eval
+ */
+apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data)
+{
+ int i;
+
+ eval->errfn = errfn;
+ eval->data = data;
+
+ eval->commands = commands;
+
+ eval->lnum = 0;
+ eval->fout = NULL;
+
+ if (eval->linebuf == NULL) {
+ eval->lsize = INIT_BUF_SIZE;
+ eval->linebuf = apr_pcalloc(eval->pool, eval->lsize);
+ }
+ if (eval->holdbuf == NULL) {
+ eval->hsize = INIT_BUF_SIZE;
+ eval->holdbuf = apr_pcalloc(eval->pool, eval->hsize);
+ }
+ if (eval->genbuf == NULL) {
+ eval->gsize = INIT_BUF_SIZE;
+ eval->genbuf = apr_pcalloc(eval->pool, eval->gsize);
+ }
+ eval->lspend = eval->linebuf;
+ eval->hspend = eval->holdbuf;
+ eval->lcomend = &eval->genbuf[71];
+
+ for (i = 0; i < sizeof(eval->abuf) / sizeof(eval->abuf[0]); i++)
+ eval->abuf[i] = NULL;
+ eval->aptr = eval->abuf;
+ eval->pending = NULL;
+ eval->inar = apr_pcalloc(eval->pool, commands->nrep * sizeof(unsigned char));
+ eval->nrep = commands->nrep;
+
+ eval->dolflag = 0;
+ eval->sflag = 0;
+ eval->jflag = 0;
+ eval->delflag = 0;
+ eval->lreadyflag = 0;
+ eval->quitflag = 0;
+ eval->finalflag = 1; /* assume we're evaluating only one file/stream */
+ eval->numpass = 0;
+ eval->nullmatch = 0;
+ eval->col = 0;
+
+ for (i = 0; i < commands->nfiles; i++) {
+ const char* filename = commands->fname[i];
+ if (apr_file_open(&eval->fcode[i], filename,
+ APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
+ eval->pool) != APR_SUCCESS) {
+ eval_errf(eval, SEDERR_COMES, filename);
+ return APR_EGENERAL;
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
+/*
+ * sed_destroy_eval
+ */
+void sed_destroy_eval(sed_eval_t *eval)
+{
+ int i;
+ /* eval->linebuf, eval->holdbuf, eval->genbuf and eval->inar are allocated
+ * on pool. It will be freed when pool will be freed */
+ for (i = 0; i < eval->commands->nfiles; i++) {
+ if (eval->fcode[i] != NULL) {
+ apr_file_close(eval->fcode[i]);
+ eval->fcode[i] = NULL;
+ }
+ }
+}
+
+/*
+ * sed_eval_file
+ */
+apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
+{
+ for (;;) {
+ char buf[1024];
+ apr_size_t read_bytes = 0;
+
+ read_bytes = sizeof(buf);
+ if (apr_file_read(fin, buf, &read_bytes) != APR_SUCCESS)
+ break;
+
+ if (sed_eval_buffer(eval, buf, read_bytes, fout) != APR_SUCCESS)
+ return APR_EGENERAL;
+
+ if (eval->quitflag)
+ return APR_SUCCESS;
+ }
+
+ return sed_finalize_eval(eval, fout);
+}
+
+/*
+ * sed_eval_buffer
+ */
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout)
+{
+ apr_status_t rv;
+
+ if (eval->quitflag)
+ return APR_SUCCESS;
+
+ if (!sed_canbe_finalized(eval->commands)) {
+ /* Commands were not finalized properly. */
+ const char* error = sed_get_finalize_error(eval->commands, eval->pool);
+ if (error) {
+ eval_errf(eval, error);
+ return APR_EGENERAL;
+ }
+ }
+
+ eval->fout = fout;
+
+ /* Process leftovers */
+ if (bufsz && eval->lreadyflag) {
+ eval->lreadyflag = 0;
+ eval->lspend--;
+ *eval->lspend = '\0';
+ rv = execute(eval);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+
+ while (bufsz) {
+ char *n;
+ int llen;
+
+ n = memchr(buf, '\n', bufsz);
+ if (n == NULL)
+ break;
+
+ llen = n - buf;
+ if (llen == bufsz - 1) {
+ /* This might be the last line; delay its processing */
+ eval->lreadyflag = 1;
+ break;
+ }
+
+ appendmem_to_linebuf(eval, buf, llen + 1);
+ --eval->lspend;
+ /* replace new line character with NULL */
+ *eval->lspend = '\0';
+ buf += (llen + 1);
+ bufsz -= (llen + 1);
+ rv = execute(eval);
+ if (rv != APR_SUCCESS)
+ return rv;
+ if (eval->quitflag)
+ break;
+ }
+
+ /* Save the leftovers for later */
+ if (bufsz) {
+ appendmem_to_linebuf(eval, buf, bufsz);
+ }
+
+ return APR_SUCCESS;
+}
+
+/*
+ * sed_finalize_eval
+ */
+apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
+{
+ if (eval->quitflag)
+ return APR_SUCCESS;
+
+ if (eval->finalflag)
+ eval->dolflag = 1;
+
+ eval->fout = fout;
+
+ /* Process leftovers */
+ if (eval->lspend > eval->linebuf) {
+ apr_status_t rv;
+
+ if (eval->lreadyflag) {
+ eval->lreadyflag = 0;
+ eval->lspend--;
+ } else {
+ /* Code can probably reach here when last character in output
+ * buffer is not a newline.
+ */
+ /* Assure space for NULL */
+ append_to_linebuf(eval, "");
+ }
+
+ *eval->lspend = '\0';
+ rv = execute(eval);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+
+ eval->quitflag = 1;
+
+ return APR_SUCCESS;
+}
+
+/*
+ * execute
+ */
+static apr_status_t execute(sed_eval_t *eval)
+{
+ sed_reptr_t *ipc = eval->commands->ptrspace;
+ step_vars_storage step_vars;
+ apr_status_t rv = APR_SUCCESS;
+
+ eval->lnum++;
+
+ eval->sflag = 0;
+
+ if (eval->pending) {
+ ipc = eval->pending;
+ eval->pending = NULL;
+ }
+
+ memset(&step_vars, 0, sizeof(step_vars));
+
+ while (ipc->command) {
+ char *p1;
+ char *p2;
+ int c;
+
+ p1 = ipc->ad1;
+ p2 = ipc->ad2;
+
+ if (p1) {
+
+ if (eval->inar[ipc->nrep]) {
+ if (*p2 == CEND) {
+ p1 = 0;
+ } else if (*p2 == CLNUM) {
+ c = (unsigned char)p2[1];
+ if (eval->lnum > eval->commands->tlno[c]) {
+ eval->inar[ipc->nrep] = 0;
+ if (ipc->negfl)
+ goto yes;
+ ipc = ipc->next;
+ continue;
+ }
+ if (eval->lnum == eval->commands->tlno[c]) {
+ eval->inar[ipc->nrep] = 0;
+ }
+ } else if (match(eval, p2, 0, &step_vars)) {
+ eval->inar[ipc->nrep] = 0;
+ }
+ } else if (*p1 == CEND) {
+ if (!eval->dolflag) {
+ if (ipc->negfl)
+ goto yes;
+ ipc = ipc->next;
+ continue;
+ }
+ } else if (*p1 == CLNUM) {
+ c = (unsigned char)p1[1];
+ if (eval->lnum != eval->commands->tlno[c]) {
+ if (ipc->negfl)
+ goto yes;
+ ipc = ipc->next;
+ continue;
+ }
+ if (p2)
+ eval->inar[ipc->nrep] = 1;
+ } else if (match(eval, p1, 0, &step_vars)) {
+ if (p2)
+ eval->inar[ipc->nrep] = 1;
+ } else {
+ if (ipc->negfl)
+ goto yes;
+ ipc = ipc->next;
+ continue;
+ }
+ }
+
+ if (ipc->negfl) {
+ ipc = ipc->next;
+ continue;
+ }
+
+yes:
+ rv = command(eval, ipc, &step_vars);
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ if (eval->quitflag)
+ return APR_SUCCESS;
+
+ if (eval->pending)
+ return APR_SUCCESS;
+
+ if (eval->delflag)
+ break;
+
+ if (eval->jflag) {
+ eval->jflag = 0;
+ if ((ipc = ipc->lb1) == 0) {
+ ipc = eval->commands->ptrspace;
+ break;
+ }
+ } else
+ ipc = ipc->next;
+ }
+
+ if (!eval->commands->nflag && !eval->delflag) {
+ rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+
+ if (eval->aptr > eval->abuf)
+ rv = arout(eval);
+
+ eval->delflag = 0;
+
+ eval->lspend = eval->linebuf;
+
+ return rv;
+}
+
+/*
+ * match
+ */
+static int match(sed_eval_t *eval, char *expbuf, int gf,
+ step_vars_storage *step_vars)
+{
+ char *p1;
+ int circf;
+
+ if(gf) {
+ if(*expbuf) return(0);
+ step_vars->locs = p1 = step_vars->loc2;
+ } else {
+ p1 = eval->linebuf;
+ step_vars->locs = 0;
+ }
+
+ circf = *expbuf++;
+ return(sed_step(p1, expbuf, circf, step_vars));
+}
+
+/*
+ * substitute
+ */
+static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
+ step_vars_storage *step_vars)
+{
+ if(match(eval, ipc->re1, 0, step_vars) == 0) return(0);
+
+ eval->numpass = 0;
+ eval->sflag = 0; /* Flags if any substitution was made */
+ if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
+ return -1;
+
+ if(ipc->gfl) {
+ while(*step_vars->loc2) {
+ if(match(eval, ipc->re1, 1, step_vars) == 0) break;
+ if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
+ return -1;
+ }
+ }
+ return(eval->sflag);
+}
+
+/*
+ * dosub
+ */
+static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
+ step_vars_storage *step_vars)
+{
+ char *lp, *sp, *rp;
+ int c;
+ apr_status_t rv = APR_SUCCESS;
+
+ if(n > 0 && n < 999) {
+ eval->numpass++;
+ if(n != eval->numpass) return APR_SUCCESS;
+ }
+ eval->sflag = 1;
+ lp = eval->linebuf;
+ sp = eval->genbuf;
+ rp = rhsbuf;
+ sp = place(eval, sp, lp, step_vars->loc1);
+ while ((c = *rp++) != 0) {
+ if (c == '&') {
+ sp = place(eval, sp, step_vars->loc1, step_vars->loc2);
+ if (sp == NULL)
+ return APR_EGENERAL;
+ }
+ else if (c == '\\') {
+ c = *rp++;
+ if (c >= '1' && c < NBRA+'1') {
+ sp = place(eval, sp, step_vars->braslist[c-'1'],
+ step_vars->braelist[c-'1']);
+ if (sp == NULL)
+ return APR_EGENERAL;
+ }
+ else
+ *sp++ = c;
+ } else
+ *sp++ = c;
+ if (sp >= eval->genbuf + eval->gsize) {
+ /* expand genbuf and set the sp appropriately */
+ grow_gen_buffer(eval, eval->gsize + 1024, &sp);
+ }
+ }
+ lp = step_vars->loc2;
+ step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
+ append_to_genbuf(eval, lp, &sp);
+ copy_to_linebuf(eval, eval->genbuf);
+ return rv;
+}
+
+/*
+ * place
+ */
+static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
+{
+ char *sp = asp;
+ int n = al2 - al1;
+ unsigned int reqsize = (sp - eval->genbuf) + n + 1;
+
+ if (eval->gsize < reqsize) {
+ grow_gen_buffer(eval, reqsize, &sp);
+ }
+ memcpy(sp, al1, n);
+ return sp + n;
+}
+
+/*
+ * command
+ */
+static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
+ step_vars_storage *step_vars)
+{
+ int i;
+ char *p1, *p2, *p3;
+ int length;
+ char sz[32]; /* 32 bytes enough to store 64 bit integer in decimal */
+ apr_status_t rv = APR_SUCCESS;
+
+
+ switch(ipc->command) {
+
+ case ACOM:
+ if(eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
+ eval_errf(eval, SEDERR_TMAMES, eval->lnum);
+ } else {
+ *eval->aptr++ = ipc;
+ *eval->aptr = NULL;
+ }
+ break;
+
+ case CCOM:
+ eval->delflag = 1;
+ if(!eval->inar[ipc->nrep] || eval->dolflag) {
+ for (p1 = ipc->re1; *p1; p1++)
+ ;
+ rv = wline(eval, ipc->re1, p1 - ipc->re1);
+ }
+ break;
+ case DCOM:
+ eval->delflag++;
+ break;
+ case CDCOM:
+ p1 = eval->linebuf;
+
+ while(*p1 != '\n') {
+ if(*p1++ == 0) {
+ eval->delflag++;
+ return APR_SUCCESS;
+ }
+ }
+
+ p1++;
+ copy_to_linebuf(eval, p1);
+ eval->jflag++;
+ break;
+
+ case EQCOM:
+ length = apr_snprintf(sz, sizeof(sz), "%d", (int) eval->lnum);
+ rv = wline(eval, sz, length);
+ break;
+
+ case GCOM:
+ copy_to_linebuf(eval, eval->holdbuf);
+ break;
+
+ case CGCOM:
+ append_to_linebuf(eval, "\n");
+ append_to_linebuf(eval, eval->holdbuf);
+ break;
+
+ case HCOM:
+ copy_to_holdbuf(eval, eval->linebuf);
+ break;
+
+ case CHCOM:
+ append_to_holdbuf(eval, "\n");
+ append_to_holdbuf(eval, eval->linebuf);
+ break;
+
+ case ICOM:
+ for (p1 = ipc->re1; *p1; p1++);
+ rv = wline(eval, ipc->re1, p1 - ipc->re1);
+ break;
+
+ case BCOM:
+ eval->jflag = 1;
+ break;
+
+
+ case LCOM:
+ p1 = eval->linebuf;
+ p2 = eval->genbuf;
+ eval->genbuf[72] = 0;
+ while(*p1)
+ if((unsigned char)*p1 >= 040) {
+ if(*p1 == 0177) {
+ p3 = rub;
+ while ((*p2++ = *p3++) != 0)
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ p2--;
+ p1++;
+ continue;
+ }
+ if(!isprint(*p1 & 0377)) {
+ *p2++ = '\\';
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ *p2++ = (*p1 >> 6) + '0';
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ *p2++ = ((*p1 >> 3) & 07) + '0';
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ *p2++ = (*p1++ & 07) + '0';
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ } else {
+ *p2++ = *p1++;
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ }
+ } else {
+ p3 = trans[(unsigned char)*p1-1];
+ while ((*p2++ = *p3++) != 0)
+ if(p2 >= eval->lcomend) {
+ *p2 = '\\';
+ rv = wline(eval, eval->genbuf,
+ strlen(eval->genbuf));
+ if (rv != APR_SUCCESS)
+ return rv;
+ p2 = eval->genbuf;
+ }
+ p2--;
+ p1++;
+ }
+ *p2 = 0;
+ rv = wline(eval, eval->genbuf, strlen(eval->genbuf));
+ break;
+
+ case NCOM:
+ if(!eval->commands->nflag) {
+ rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+
+ if(eval->aptr > eval->abuf) {
+ rv = arout(eval);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+ eval->lspend = eval->linebuf;
+ eval->pending = ipc->next;
+
+ break;
+ case CNCOM:
+ if(eval->aptr > eval->abuf) {
+ rv = arout(eval);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+ append_to_linebuf(eval, "\n");
+ eval->pending = ipc->next;
+ break;
+
+ case PCOM:
+ rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+ break;
+ case CPCOM:
+ for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
+ rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
+ break;
+
+ case QCOM:
+ if (!eval->commands->nflag) {
+ rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
+ if (rv != APR_SUCCESS)
+ break;
+ }
+
+ if(eval->aptr > eval->abuf) {
+ rv = arout(eval);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+
+ eval->quitflag = 1;
+ break;
+ case RCOM:
+ if(eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
+ eval_errf(eval, SEDERR_TMRMES, eval->lnum);
+ } else {
+ *eval->aptr++ = ipc;
+ *eval->aptr = NULL;
+ }
+ break;
+
+ case SCOM:
+ i = substitute(eval, ipc, step_vars);
+ if (i == -1) {
+ return APR_EGENERAL;
+ }
+ if(ipc->pfl && eval->commands->nflag && i) {
+ if(ipc->pfl == 1) {
+ rv = wline(eval, eval->linebuf, eval->lspend -
+ eval->linebuf);
+ if (rv != APR_SUCCESS)
+ return rv;
+ } else {
+ for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
+ rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+ }
+ if (i && (ipc->findex >= 0) && eval->fcode[ipc->findex])
+ apr_file_printf(eval->fcode[ipc->findex], "%s\n",
+ eval->linebuf);
+ break;
+
+ case TCOM:
+ if(eval->sflag == 0) break;
+ eval->sflag = 0;
+ eval->jflag = 1;
+ break;
+
+ case WCOM:
+ if (ipc->findex >= 0)
+ apr_file_printf(eval->fcode[ipc->findex], "%s\n",
+ eval->linebuf);
+ break;
+ case XCOM:
+ copy_to_genbuf(eval, eval->linebuf);
+ copy_to_linebuf(eval, eval->holdbuf);
+ copy_to_holdbuf(eval, eval->genbuf);
+ break;
+
+ case YCOM:
+ p1 = eval->linebuf;
+ p2 = ipc->re1;
+ while((*p1 = p2[(unsigned char)*p1]) != 0) p1++;
+ break;
+ }
+ return rv;
+}
+
+/*
+ * arout
+ */
+static apr_status_t arout(sed_eval_t *eval)
+{
+ apr_status_t rv = APR_SUCCESS;
+ eval->aptr = eval->abuf - 1;
+ while (*++eval->aptr) {
+ if ((*eval->aptr)->command == ACOM) {
+ char *p1;
+
+ for (p1 = (*eval->aptr)->re1; *p1; p1++);
+ rv = wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1);
+ if (rv != APR_SUCCESS)
+ return rv;
+ } else {
+ apr_file_t *fi = NULL;
+ char buf[512];
+ apr_size_t n = sizeof(buf);
+
+ if (apr_file_open(&fi, (*eval->aptr)->re1, APR_READ, 0, eval->pool)
+ != APR_SUCCESS)
+ continue;
+ while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) {
+ if (n == 0)
+ break;
+ rv = eval->writefn(eval->fout, buf, n);
+ if (rv != APR_SUCCESS) {
+ apr_file_close(fi);
+ return rv;
+ }
+ n = sizeof(buf);
+ }
+ apr_file_close(fi);
+ }
+ }
+ eval->aptr = eval->abuf;
+ *eval->aptr = NULL;
+ return rv;
+}
+
+/*
+ * wline
+ */
+static apr_status_t wline(sed_eval_t *eval, char *buf, int sz)
+{
+ apr_status_t rv = APR_SUCCESS;
+ rv = eval->writefn(eval->fout, buf, sz);
+ if (rv != APR_SUCCESS)
+ return rv;
+ rv = eval->writefn(eval->fout, "\n", 1);
+ return rv;
+}
+