summaryrefslogtreecommitdiffstats
path: root/modules/generators
diff options
context:
space:
mode:
Diffstat (limited to 'modules/generators')
-rw-r--r--modules/generators/.indent.pro54
-rw-r--r--modules/generators/Makefile.in3
-rw-r--r--modules/generators/NWGNUautoindex249
-rw-r--r--modules/generators/NWGNUinfo248
-rw-r--r--modules/generators/NWGNUmakefile249
-rw-r--r--modules/generators/NWGNUmod_asis249
-rw-r--r--modules/generators/NWGNUmod_cgi249
-rw-r--r--modules/generators/NWGNUstatus248
-rw-r--r--modules/generators/config5.m481
-rw-r--r--modules/generators/mod_asis.c128
-rw-r--r--modules/generators/mod_asis.dep56
-rw-r--r--modules/generators/mod_asis.dsp111
-rw-r--r--modules/generators/mod_asis.exp1
-rw-r--r--modules/generators/mod_asis.mak353
-rw-r--r--modules/generators/mod_autoindex.c2348
-rw-r--r--modules/generators/mod_autoindex.dep61
-rw-r--r--modules/generators/mod_autoindex.dsp111
-rw-r--r--modules/generators/mod_autoindex.exp1
-rw-r--r--modules/generators/mod_autoindex.mak353
-rw-r--r--modules/generators/mod_cgi.c1281
-rw-r--r--modules/generators/mod_cgi.dep64
-rw-r--r--modules/generators/mod_cgi.dsp115
-rw-r--r--modules/generators/mod_cgi.exp1
-rw-r--r--modules/generators/mod_cgi.h67
-rw-r--r--modules/generators/mod_cgi.mak353
-rw-r--r--modules/generators/mod_cgid.c1980
-rw-r--r--modules/generators/mod_cgid.exp1
-rw-r--r--modules/generators/mod_info.c1011
-rw-r--r--modules/generators/mod_info.dep66
-rw-r--r--modules/generators/mod_info.dsp111
-rw-r--r--modules/generators/mod_info.exp1
-rw-r--r--modules/generators/mod_info.mak353
-rw-r--r--modules/generators/mod_status.c1051
-rw-r--r--modules/generators/mod_status.dep60
-rw-r--r--modules/generators/mod_status.dsp111
-rw-r--r--modules/generators/mod_status.exp1
-rw-r--r--modules/generators/mod_status.h64
-rw-r--r--modules/generators/mod_status.mak353
-rw-r--r--modules/generators/mod_suexec.c139
-rw-r--r--modules/generators/mod_suexec.h33
40 files changed, 12369 insertions, 0 deletions
diff --git a/modules/generators/.indent.pro b/modules/generators/.indent.pro
new file mode 100644
index 0000000..a9fbe9f
--- /dev/null
+++ b/modules/generators/.indent.pro
@@ -0,0 +1,54 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
+-TBUFF
+-TFILE
+-TTRANS
+-TUINT4
+-T_trans
+-Tallow_options_t
+-Tapache_sfio
+-Tarray_header
+-Tbool_int
+-Tbuf_area
+-Tbuff_struct
+-Tbuffy
+-Tcmd_how
+-Tcmd_parms
+-Tcommand_rec
+-Tcommand_struct
+-Tconn_rec
+-Tcore_dir_config
+-Tcore_server_config
+-Tdir_maker_func
+-Tevent
+-Tglobals_s
+-Thandler_func
+-Thandler_rec
+-Tjoblist_s
+-Tlisten_rec
+-Tmerger_func
+-Tmode_t
+-Tmodule
+-Tmodule_struct
+-Tmutex
+-Tn_long
+-Tother_child_rec
+-Toverrides_t
+-Tparent_score
+-Tpid_t
+-Tpiped_log
+-Tpool
+-Trequest_rec
+-Trequire_line
+-Trlim_t
+-Tscoreboard
+-Tsemaphore
+-Tserver_addr_rec
+-Tserver_rec
+-Tserver_rec_chain
+-Tshort_score
+-Ttable
+-Ttable_entry
+-Tthread
+-Tu_wide_int
+-Tvtime_t
+-Twide_int
diff --git a/modules/generators/Makefile.in b/modules/generators/Makefile.in
new file mode 100644
index 0000000..167b343
--- /dev/null
+++ b/modules/generators/Makefile.in
@@ -0,0 +1,3 @@
+
+include $(top_srcdir)/build/special.mk
+
diff --git a/modules/generators/NWGNUautoindex b/modules/generators/NWGNUautoindex
new file mode 100644
index 0000000..e8080c3
--- /dev/null
+++ b/modules/generators/NWGNUautoindex
@@ -0,0 +1,249 @@
+#
+# 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 \
+ $(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 += \
+ $(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 = autoindex
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Autoindex Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Autoindex 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)/autoindex.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_autoindex.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 = \
+ autoindex_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/generators/NWGNUinfo b/modules/generators/NWGNUinfo
new file mode 100644
index 0000000..810db8a
--- /dev/null
+++ b/modules/generators/NWGNUinfo
@@ -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 = info
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Info Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Info 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)/info.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_info.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 = \
+ info_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/generators/NWGNUmakefile b/modules/generators/NWGNUmakefile
new file mode 100644
index 0000000..df9cfec
--- /dev/null
+++ b/modules/generators/NWGNUmakefile
@@ -0,0 +1,249 @@
+#
+# 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 += \
+ $(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 =
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION =
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME =
+
+#
+# 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 =
+
+
+#
+# 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_asis.nlm \
+ $(OBJDIR)/autoindex.nlm \
+ $(OBJDIR)/mod_cgi.nlm \
+ $(OBJDIR)/info.nlm \
+ $(OBJDIR)/status.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 = \
+ $(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 = \
+ $(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 = \
+ $(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 = \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(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
+ $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/)
+
+#
+# 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/generators/NWGNUmod_asis b/modules/generators/NWGNUmod_asis
new file mode 100644
index 0000000..c7df5ae
--- /dev/null
+++ b/modules/generators/NWGNUmod_asis
@@ -0,0 +1,249 @@
+#
+# 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 \
+ $(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 += \
+ $(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_asis
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) ASIS Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Mod_asis 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_asis.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_asis.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 = \
+ asis_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/generators/NWGNUmod_cgi b/modules/generators/NWGNUmod_cgi
new file mode 100644
index 0000000..bbb9578
--- /dev/null
+++ b/modules/generators/NWGNUmod_cgi
@@ -0,0 +1,249 @@
+#
+# 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 \
+ $(AP_WORK)/modules/http \
+ $(AP_WORK)/modules/filters \
+ $(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_cgi
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) CGI Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Mod_cgi 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_cgi.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_cgi.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 = \
+ cgi_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/generators/NWGNUstatus b/modules/generators/NWGNUstatus
new file mode 100644
index 0000000..1dc850e
--- /dev/null
+++ b/modules/generators/NWGNUstatus
@@ -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 = status
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Status Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Status 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)/status.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_status.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 = \
+ status_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/generators/config5.m4 b/modules/generators/config5.m4
new file mode 100644
index 0000000..bf29521
--- /dev/null
+++ b/modules/generators/config5.m4
@@ -0,0 +1,81 @@
+dnl modules enabled in this directory by default
+
+dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]])
+
+APACHE_MODPATH_INIT(generators)
+
+APACHE_MODULE(status, process/thread monitoring, , , yes)
+APACHE_MODULE(autoindex, directory listing, , , yes)
+APACHE_MODULE(asis, as-is filetypes, , , )
+APACHE_MODULE(info, server information, , , most)
+APACHE_MODULE(suexec, set uid and gid for spawned processes, , , no, [
+ other_targets=suexec ] )
+
+# Is mod_cgid needed?
+case $host in
+ *mingw*)
+ dnl No fork+thread+fd issues, and cgid doesn't work anyway.
+ cgid_needed="no"
+ ;;
+ *)
+ if ap_mpm_is_threaded; then
+ dnl if we are using a threaded MPM on Unix, we can get better
+ dnl performance with mod_cgid, and also avoid potential issues
+ dnl with forking from a threaded process.
+ cgid_needed="yes"
+ else
+ dnl if we are using a non-threaded MPM, it makes little sense to
+ dnl use mod_cgid, and it just opens up holes we don't need.
+ cgid_needed="no"
+ fi
+ ;;
+esac
+
+if test $cgid_needed = "yes"; then
+ APACHE_MODULE(cgid, CGI scripts. Enabled by default with threaded MPMs, , , most, [
+ case $host in
+ *-solaris2*)
+ case `uname -r` in
+ 5.10)
+ dnl Does the system have the appropriate patches?
+ case `uname -p` in
+ i386)
+ patch_id="120665"
+ ;;
+ sparc)
+ patch_id="120664"
+ ;;
+ *)
+ AC_MSG_WARN([Unknown platform])
+ patch_id="120664"
+ ;;
+ esac
+ AC_MSG_CHECKING([for Solaris patch $patch_id])
+ showrev -p | grep "$patch_id" >/dev/null 2>&1
+ if test $? -eq 1; then
+ dnl Solaris 11 (next release) as of snv_19 doesn't have this problem.
+ dnl It may be possible to use /kernel/drv/tl from later releases.
+ AC_MSG_ERROR([Please apply either patch # 120664 (Sparc) or # 120665 (x86).
+Without these patches, mod_cgid is non-functional on Solaris 10 due to an OS
+bug with AF_UNIX sockets.
+If you can not apply these patches, you can do one of the following:
+ - run configure with --disable-cgid
+ - switch to the prefork MPM
+For more info: <http://issues.apache.org/bugzilla/show_bug.cgi?id=34264>])
+ else
+ AC_MSG_RESULT(yes)
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ ])
+ APACHE_MODULE(cgi, CGI scripts. Enabled by default with non-threaded MPMs, , , no)
+else
+ APACHE_MODULE(cgi, CGI scripts. Enabled by default with non-threaded MPMs, , , most)
+ APACHE_MODULE(cgid, CGI scripts. Enabled by default with threaded MPMs, , , no)
+fi
+
+APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
+
+APACHE_MODPATH_FINISH
diff --git a/modules/generators/mod_asis.c b/modules/generators/mod_asis.c
new file mode 100644
index 0000000..c2b651b
--- /dev/null
+++ b/modules/generators/mod_asis.c
@@ -0,0 +1,128 @@
+/* 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 "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "http_main.h"
+#include "http_request.h"
+
+#include "mod_core.h"
+
+#define ASIS_MAGIC_TYPE "httpd/send-as-is"
+
+static int asis_handler(request_rec *r)
+{
+ apr_file_t *f;
+ apr_status_t rv;
+ const char *location;
+
+ if (strcmp(r->handler, ASIS_MAGIC_TYPE) && strcmp(r->handler, "send-as-is")) {
+ return DECLINED;
+ }
+
+ r->allowed |= (AP_METHOD_BIT << M_GET);
+ if (r->method_number != M_GET) {
+ return DECLINED;
+ }
+
+ if (r->finfo.filetype == APR_NOFILE) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01233)
+ "File does not exist: %s", r->filename);
+ return HTTP_NOT_FOUND;
+ }
+
+ if ((rv = apr_file_open(&f, r->filename, APR_READ,
+ APR_OS_DEFAULT, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01234)
+ "file permissions deny server access: %s", r->filename);
+ return HTTP_FORBIDDEN;
+ }
+
+ ap_scan_script_header_err_ex(r, f, NULL, APLOG_MODULE_INDEX);
+ location = apr_table_get(r->headers_out, "Location");
+
+ if (location && location[0] == '/' &&
+ ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
+
+ apr_file_close(f);
+
+ /* Internal redirect -- fake-up a pseudo-request */
+ r->status = HTTP_OK;
+
+ /* This redirect needs to be a GET no matter what the original
+ * method was.
+ */
+ r->method = "GET";
+ r->method_number = M_GET;
+
+ ap_internal_redirect_handler(location, r);
+ return OK;
+ }
+
+ if (!r->header_only) {
+ conn_rec *c = r->connection;
+ apr_bucket_brigade *bb;
+ apr_bucket *b;
+ apr_off_t pos = 0;
+
+ rv = apr_file_seek(f, APR_CUR, &pos);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01235)
+ "mod_asis: failed to find end-of-headers position "
+ "for %s", r->filename);
+ apr_file_close(f);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ bb = apr_brigade_create(r->pool, c->bucket_alloc);
+ apr_brigade_insert_file(bb, f, pos, r->finfo.size - pos, r->pool);
+
+ b = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ rv = ap_pass_brigade(r->output_filters, bb);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01236)
+ "mod_asis: ap_pass_brigade failed for file %s", r->filename);
+ return AP_FILTER_ERROR;
+ }
+ }
+ else {
+ apr_file_close(f);
+ }
+
+ return OK;
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_hook_handler(asis_handler,NULL,NULL,APR_HOOK_MIDDLE);
+}
+
+AP_DECLARE_MODULE(asis) =
+{
+ 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 /* register hooks */
+};
diff --git a/modules/generators/mod_asis.dep b/modules/generators/mod_asis.dep
new file mode 100644
index 0000000..cbfe300
--- /dev/null
+++ b/modules/generators/mod_asis.dep
@@ -0,0 +1,56 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_asis.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_asis.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_log.h"\
+ "..\..\include\http_main.h"\
+ "..\..\include\http_protocol.h"\
+ "..\..\include\http_request.h"\
+ "..\..\include\httpd.h"\
+ "..\..\include\mod_core.h"\
+ "..\..\include\os.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\include\util_script.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.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-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+
diff --git a/modules/generators/mod_asis.dsp b/modules/generators/mod_asis.dsp
new file mode 100644
index 0000000..bad34f0
--- /dev/null
+++ b/modules/generators/mod_asis.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_asis" - 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_asis - 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_asis.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_asis.mak" CFG="mod_asis - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_asis - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_asis - 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_asis - 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_asis_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_asis.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_asis.so" /d LONG_NAME="asis_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_asis.so" /base:@..\..\os\win32\BaseAddr.ref,mod_asis.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_asis.so" /base:@..\..\os\win32\BaseAddr.ref,mod_asis.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_asis.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_asis - 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_asis_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_asis.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_asis.so" /d LONG_NAME="asis_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_asis.so" /base:@..\..\os\win32\BaseAddr.ref,mod_asis.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_asis.so" /base:@..\..\os\win32\BaseAddr.ref,mod_asis.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_asis.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_asis - Win32 Release"
+# Name "mod_asis - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_asis.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/generators/mod_asis.exp b/modules/generators/mod_asis.exp
new file mode 100644
index 0000000..4f347d9
--- /dev/null
+++ b/modules/generators/mod_asis.exp
@@ -0,0 +1 @@
+asis_module
diff --git a/modules/generators/mod_asis.mak b/modules/generators/mod_asis.mak
new file mode 100644
index 0000000..f069aac
--- /dev/null
+++ b/modules/generators/mod_asis.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_asis.dsp
+!IF "$(CFG)" == ""
+CFG=mod_asis - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_asis - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_asis - Win32 Release" && "$(CFG)" != "mod_asis - 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_asis.mak" CFG="mod_asis - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_asis - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_asis - 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_asis - 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_asis.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_asis.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_asis.obj"
+ -@erase "$(INTDIR)\mod_asis.res"
+ -@erase "$(INTDIR)\mod_asis_src.idb"
+ -@erase "$(INTDIR)\mod_asis_src.pdb"
+ -@erase "$(OUTDIR)\mod_asis.exp"
+ -@erase "$(OUTDIR)\mod_asis.lib"
+ -@erase "$(OUTDIR)\mod_asis.pdb"
+ -@erase "$(OUTDIR)\mod_asis.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_asis_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_asis.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_asis.so" /d LONG_NAME="asis_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_asis.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_asis.pdb" /debug /out:"$(OUTDIR)\mod_asis.so" /implib:"$(OUTDIR)\mod_asis.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_asis.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_asis.obj" \
+ "$(INTDIR)\mod_asis.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_asis.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_asis.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_asis.so"
+ if exist .\Release\mod_asis.so.manifest mt.exe -manifest .\Release\mod_asis.so.manifest -outputresource:.\Release\mod_asis.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_asis - 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_asis.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_asis.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_asis.obj"
+ -@erase "$(INTDIR)\mod_asis.res"
+ -@erase "$(INTDIR)\mod_asis_src.idb"
+ -@erase "$(INTDIR)\mod_asis_src.pdb"
+ -@erase "$(OUTDIR)\mod_asis.exp"
+ -@erase "$(OUTDIR)\mod_asis.lib"
+ -@erase "$(OUTDIR)\mod_asis.pdb"
+ -@erase "$(OUTDIR)\mod_asis.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_asis_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_asis.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_asis.so" /d LONG_NAME="asis_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_asis.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_asis.pdb" /debug /out:"$(OUTDIR)\mod_asis.so" /implib:"$(OUTDIR)\mod_asis.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_asis.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_asis.obj" \
+ "$(INTDIR)\mod_asis.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_asis.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_asis.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_asis.so"
+ if exist .\Debug\mod_asis.so.manifest mt.exe -manifest .\Debug\mod_asis.so.manifest -outputresource:.\Debug\mod_asis.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_asis.dep")
+!INCLUDE "mod_asis.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_asis.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_asis - Win32 Release" || "$(CFG)" == "mod_asis - Win32 Debug"
+
+!IF "$(CFG)" == "mod_asis - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_asis - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_asis - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_asis - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_asis - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_asis - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_asis - Win32 Release"
+
+
+"$(INTDIR)\mod_asis.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_asis.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_asis.so" /d LONG_NAME="asis_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_asis - Win32 Debug"
+
+
+"$(INTDIR)\mod_asis.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_asis.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_asis.so" /d LONG_NAME="asis_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_asis.c
+
+"$(INTDIR)\mod_asis.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/generators/mod_autoindex.c b/modules/generators/mod_autoindex.c
new file mode 100644
index 0000000..9094e30
--- /dev/null
+++ b/modules/generators/mod_autoindex.c
@@ -0,0 +1,2348 @@
+/* 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_autoindex.c: Handles the on-the-fly html index generation
+ *
+ * Rob McCool
+ * 3/23/93
+ *
+ * Adapted to Apache by rst.
+ *
+ * Version sort added by Martin Pool <mbp@humbug.org.au>.
+ */
+
+#include "apr_strings.h"
+#include "apr_fnmatch.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_request.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+#include "mod_core.h"
+
+module AP_MODULE_DECLARE_DATA autoindex_module;
+
+/****************************************************************
+ *
+ * Handling configuration directives...
+ */
+
+#define NO_OPTIONS (1 << 0) /* Indexing options */
+#define ICONS_ARE_LINKS (1 << 1)
+#define SCAN_HTML_TITLES (1 << 2)
+#define SUPPRESS_ICON (1 << 3)
+#define SUPPRESS_LAST_MOD (1 << 4)
+#define SUPPRESS_SIZE (1 << 5)
+#define SUPPRESS_DESC (1 << 6)
+#define SUPPRESS_PREAMBLE (1 << 7)
+#define SUPPRESS_COLSORT (1 << 8)
+#define SUPPRESS_RULES (1 << 9)
+#define FOLDERS_FIRST (1 << 10)
+#define VERSION_SORT (1 << 11)
+#define TRACK_MODIFIED (1 << 12)
+#define FANCY_INDEXING (1 << 13)
+#define TABLE_INDEXING (1 << 14)
+#define IGNORE_CLIENT (1 << 15)
+#define IGNORE_CASE (1 << 16)
+#define EMIT_XHTML (1 << 17)
+#define SHOW_FORBIDDEN (1 << 18)
+#define ADDALTCLASS (1 << 19)
+#define OPTION_UNSET (1 << 20)
+
+#define K_NOADJUST 0
+#define K_ADJUST 1
+#define K_UNSET 2
+
+/*
+ * Define keys for sorting.
+ */
+#define K_NAME 'N' /* Sort by file name (default) */
+#define K_LAST_MOD 'M' /* Last modification date */
+#define K_SIZE 'S' /* Size (absolute, not as displayed) */
+#define K_DESC 'D' /* Description */
+#define K_VALID "NMSD" /* String containing _all_ valid K_ opts */
+
+#define D_ASCENDING 'A'
+#define D_DESCENDING 'D'
+#define D_VALID "AD" /* String containing _all_ valid D_ opts */
+
+/*
+ * These are the dimensions of the default icons supplied with Apache.
+ */
+#define DEFAULT_ICON_WIDTH 20
+#define DEFAULT_ICON_HEIGHT 22
+
+/*
+ * Other default dimensions.
+ */
+#define DEFAULT_NAME_WIDTH 23
+#define DEFAULT_DESC_WIDTH 23
+
+struct item {
+ char *type;
+ char *apply_to;
+ char *apply_path;
+ char *data;
+};
+
+typedef struct ai_desc_t {
+ char *pattern;
+ char *description;
+ int full_path;
+ int wildcards;
+} ai_desc_t;
+
+typedef struct autoindex_config_struct {
+
+ char *default_icon;
+ char *style_sheet;
+ char *head_insert;
+ char *header;
+ char *readme;
+ apr_int32_t opts;
+ apr_int32_t incremented_opts;
+ apr_int32_t decremented_opts;
+ int name_width;
+ int name_adjust;
+ int desc_width;
+ int desc_adjust;
+ int icon_width;
+ int icon_height;
+ char default_keyid;
+ char default_direction;
+
+ apr_array_header_t *icon_list;
+ apr_array_header_t *alt_list;
+ apr_array_header_t *desc_list;
+ apr_array_header_t *ign_list;
+ int ign_noinherit;
+
+ char *ctype;
+ char *charset;
+ char *datetime_format;
+} autoindex_config_rec;
+
+static char c_by_encoding, c_by_type, c_by_path;
+
+#define BY_ENCODING &c_by_encoding
+#define BY_TYPE &c_by_type
+#define BY_PATH &c_by_path
+
+static APR_INLINE int response_is_html(request_rec *r)
+{
+ char *ctype = ap_field_noparam(r->pool, r->content_type);
+
+ return !ap_cstr_casecmp(ctype, "text/html")
+ || !ap_cstr_casecmp(ctype, "application/xhtml+xml");
+}
+
+/*
+ * This routine puts the standard HTML header at the top of the index page.
+ * We include the DOCTYPE because we may be using features therefrom (i.e.,
+ * HEIGHT and WIDTH attributes on the icons if we're FancyIndexing).
+ */
+static void emit_preamble(request_rec *r, int xhtml, const char *title)
+{
+ autoindex_config_rec *d;
+
+ d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config,
+ &autoindex_module);
+
+ if (xhtml) {
+ ap_rvputs(r, DOCTYPE_XHTML_1_0T,
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+ " <head>\n <title>Index of ", title,
+ "</title>\n", NULL);
+ } else {
+ ap_rvputs(r, DOCTYPE_HTML_3_2,
+ "<html>\n <head>\n"
+ " <title>Index of ", title,
+ "</title>\n", NULL);
+ }
+
+ if (d->style_sheet != NULL) {
+ ap_rvputs(r, " <link rel=\"stylesheet\" href=\"", d->style_sheet,
+ "\" type=\"text/css\"", xhtml ? " />\n" : ">\n", NULL);
+ }
+ if (d->head_insert != NULL) {
+ ap_rputs(d->head_insert, r);
+ }
+ ap_rputs(" </head>\n <body>\n", r);
+}
+
+static void push_item(apr_array_header_t *arr, char *type, const char *to,
+ const char *path, const char *data)
+{
+ struct item *p = (struct item *) apr_array_push(arr);
+
+ if (!to) {
+ to = "";
+ }
+ if (!path) {
+ path = "";
+ }
+
+ p->type = type;
+ p->data = apr_pstrdup(arr->pool, data);
+ p->apply_path = apr_pstrcat(arr->pool, path, "*", NULL);
+
+ if ((type == BY_PATH) && (!ap_is_matchexp(to))) {
+ p->apply_to = apr_pstrcat(arr->pool, "*", to, NULL);
+ }
+ else {
+ p->apply_to = apr_pstrdup(arr->pool, to);
+ }
+}
+
+static const char *add_alt(cmd_parms *cmd, void *d, const char *alt,
+ const char *to)
+{
+ if (cmd->info == BY_PATH) {
+ if (!strcmp(to, "**DIRECTORY**")) {
+ to = "^^DIRECTORY^^";
+ }
+ }
+ if (cmd->info == BY_ENCODING) {
+ char *tmp = apr_pstrdup(cmd->temp_pool, to);
+ ap_str_tolower(tmp);
+ to = tmp;
+ }
+
+ push_item(((autoindex_config_rec *) d)->alt_list, cmd->info, to,
+ cmd->path, alt);
+ return NULL;
+}
+
+static const char *add_icon(cmd_parms *cmd, void *d, const char *icon,
+ const char *to)
+{
+ char *iconbak = apr_pstrdup(cmd->temp_pool, icon);
+
+ if (icon[0] == '(') {
+ char *alt;
+ char *cl = strchr(iconbak, ')');
+
+ if (cl == NULL) {
+ return "missing closing paren";
+ }
+ alt = ap_getword_nc(cmd->temp_pool, &iconbak, ',');
+ *cl = '\0'; /* Lose closing paren */
+ add_alt(cmd, d, &alt[1], to);
+ }
+ if (cmd->info == BY_PATH) {
+ if (!strcmp(to, "**DIRECTORY**")) {
+ to = "^^DIRECTORY^^";
+ }
+ }
+ if (cmd->info == BY_ENCODING) {
+ char *tmp = apr_pstrdup(cmd->temp_pool, to);
+ ap_str_tolower(tmp);
+ to = tmp;
+ }
+
+ push_item(((autoindex_config_rec *) d)->icon_list, cmd->info, to,
+ cmd->path, iconbak);
+ return NULL;
+}
+
+/*
+ * Add description text for a filename pattern. If the pattern has
+ * wildcards already (or we need to add them), add leading and
+ * trailing wildcards to it to ensure substring processing. If the
+ * pattern contains a '/' anywhere, force wildcard matching mode,
+ * add a slash to the prefix so that "bar/bletch" won't be matched
+ * by "foobar/bletch", and make a note that there's a delimiter;
+ * the matching routine simplifies to just the actual filename
+ * whenever it can. This allows definitions in parent directories
+ * to be made for files in subordinate ones using relative paths.
+ */
+
+/*
+ * Absent a strcasestr() function, we have to force wildcards on
+ * systems for which "AAA" and "aaa" mean the same file.
+ */
+#ifdef CASE_BLIND_FILESYSTEM
+#define WILDCARDS_REQUIRED 1
+#else
+#define WILDCARDS_REQUIRED 0
+#endif
+
+static const char *add_desc(cmd_parms *cmd, void *d, const char *desc,
+ const char *to)
+{
+ autoindex_config_rec *dcfg = (autoindex_config_rec *) d;
+ ai_desc_t *desc_entry;
+ char *prefix = "";
+
+ desc_entry = (ai_desc_t *) apr_array_push(dcfg->desc_list);
+ desc_entry->full_path = (ap_strchr_c(to, '/') == NULL) ? 0 : 1;
+ desc_entry->wildcards = (WILDCARDS_REQUIRED
+ || desc_entry->full_path
+ || apr_fnmatch_test(to));
+ if (desc_entry->wildcards) {
+ prefix = desc_entry->full_path ? "*/" : "*";
+ desc_entry->pattern = apr_pstrcat(dcfg->desc_list->pool,
+ prefix, to, "*", NULL);
+ }
+ else {
+ desc_entry->pattern = apr_pstrdup(dcfg->desc_list->pool, to);
+ }
+ desc_entry->description = apr_pstrdup(dcfg->desc_list->pool, desc);
+ return NULL;
+}
+
+static const char *add_ignore(cmd_parms *cmd, void *d, const char *ext)
+{
+ push_item(((autoindex_config_rec *) d)->ign_list, 0, ext, cmd->path, NULL);
+ return NULL;
+}
+
+static const char *add_opts(cmd_parms *cmd, void *d, int argc, char *const argv[])
+{
+ int i;
+ char *w;
+ apr_int32_t opts;
+ apr_int32_t opts_add;
+ apr_int32_t opts_remove;
+ char action;
+ autoindex_config_rec *d_cfg = (autoindex_config_rec *) d;
+
+ opts = d_cfg->opts;
+ opts_add = d_cfg->incremented_opts;
+ opts_remove = d_cfg->decremented_opts;
+
+ for (i = 0; i < argc; i++) {
+ int option = 0;
+ w = argv[i];
+
+ if ((*w == '+') || (*w == '-')) {
+ action = *(w++);
+ }
+ else {
+ action = '\0';
+ }
+ if (!strcasecmp(w, "FancyIndexing")) {
+ option = FANCY_INDEXING;
+ }
+ else if (!strcasecmp(w, "FoldersFirst")) {
+ option = FOLDERS_FIRST;
+ }
+ else if (!strcasecmp(w, "HTMLTable")) {
+ option = TABLE_INDEXING;
+ }
+ else if (!strcasecmp(w, "IconsAreLinks")) {
+ option = ICONS_ARE_LINKS;
+ }
+ else if (!strcasecmp(w, "IgnoreCase")) {
+ option = IGNORE_CASE;
+ }
+ else if (!strcasecmp(w, "IgnoreClient")) {
+ option = IGNORE_CLIENT;
+ }
+ else if (!strcasecmp(w, "ScanHTMLTitles")) {
+ option = SCAN_HTML_TITLES;
+ }
+ else if (!strcasecmp(w, "SuppressColumnSorting")) {
+ option = SUPPRESS_COLSORT;
+ }
+ else if (!strcasecmp(w, "SuppressDescription")) {
+ option = SUPPRESS_DESC;
+ }
+ else if (!strcasecmp(w, "SuppressHTMLPreamble")) {
+ option = SUPPRESS_PREAMBLE;
+ }
+ else if (!strcasecmp(w, "SuppressIcon")) {
+ option = SUPPRESS_ICON;
+ }
+ else if (!strcasecmp(w, "SuppressLastModified")) {
+ option = SUPPRESS_LAST_MOD;
+ }
+ else if (!strcasecmp(w, "SuppressSize")) {
+ option = SUPPRESS_SIZE;
+ }
+ else if (!strcasecmp(w, "SuppressRules")) {
+ option = SUPPRESS_RULES;
+ }
+ else if (!strcasecmp(w, "TrackModified")) {
+ option = TRACK_MODIFIED;
+ }
+ else if (!strcasecmp(w, "VersionSort")) {
+ option = VERSION_SORT;
+ }
+ else if (!strcasecmp(w, "XHTML")) {
+ option = EMIT_XHTML;
+ }
+ else if (!strcasecmp(w, "ShowForbidden")) {
+ option = SHOW_FORBIDDEN;
+ }
+ else if (!strcasecmp(w, "AddAltClass")) {
+ option = ADDALTCLASS;
+ }
+ else if (!strcasecmp(w, "None")) {
+ if (action != '\0') {
+ return "Cannot combine '+' or '-' with 'None' keyword";
+ }
+ opts = NO_OPTIONS;
+ opts_add = 0;
+ opts_remove = 0;
+ }
+ else if (!strcasecmp(w, "IconWidth")) {
+ if (action != '-') {
+ d_cfg->icon_width = DEFAULT_ICON_WIDTH;
+ }
+ else {
+ d_cfg->icon_width = 0;
+ }
+ }
+ else if (!strncasecmp(w, "IconWidth=", 10)) {
+ if (action == '-') {
+ return "Cannot combine '-' with IconWidth=n";
+ }
+ d_cfg->icon_width = atoi(&w[10]);
+ }
+ else if (!strcasecmp(w, "IconHeight")) {
+ if (action != '-') {
+ d_cfg->icon_height = DEFAULT_ICON_HEIGHT;
+ }
+ else {
+ d_cfg->icon_height = 0;
+ }
+ }
+ else if (!strncasecmp(w, "IconHeight=", 11)) {
+ if (action == '-') {
+ return "Cannot combine '-' with IconHeight=n";
+ }
+ d_cfg->icon_height = atoi(&w[11]);
+ }
+ else if (!strcasecmp(w, "NameWidth")) {
+ if (action != '-') {
+ return "NameWidth with no value may only appear as "
+ "'-NameWidth'";
+ }
+ d_cfg->name_width = DEFAULT_NAME_WIDTH;
+ d_cfg->name_adjust = K_NOADJUST;
+ }
+ else if (!strncasecmp(w, "NameWidth=", 10)) {
+ if (action == '-') {
+ return "Cannot combine '-' with NameWidth=n";
+ }
+ if (w[10] == '*') {
+ d_cfg->name_adjust = K_ADJUST;
+ }
+ else {
+ int width = atoi(&w[10]);
+
+ if (width && (width < 5)) {
+ return "NameWidth value must be greater than 5";
+ }
+ d_cfg->name_width = width;
+ d_cfg->name_adjust = K_NOADJUST;
+ }
+ }
+ else if (!strcasecmp(w, "DescriptionWidth")) {
+ if (action != '-') {
+ return "DescriptionWidth with no value may only appear as "
+ "'-DescriptionWidth'";
+ }
+ d_cfg->desc_width = DEFAULT_DESC_WIDTH;
+ d_cfg->desc_adjust = K_NOADJUST;
+ }
+ else if (!strncasecmp(w, "DescriptionWidth=", 17)) {
+ if (action == '-') {
+ return "Cannot combine '-' with DescriptionWidth=n";
+ }
+ if (w[17] == '*') {
+ d_cfg->desc_adjust = K_ADJUST;
+ }
+ else {
+ int width = atoi(&w[17]);
+
+ if (width && (width < 12)) {
+ return "DescriptionWidth value must be greater than 12";
+ }
+ d_cfg->desc_width = width;
+ d_cfg->desc_adjust = K_NOADJUST;
+ }
+ }
+ else if (!strncasecmp(w, "Type=", 5)) {
+ d_cfg->ctype = apr_pstrdup(cmd->pool, &w[5]);
+ }
+ else if (!strncasecmp(w, "Charset=", 8)) {
+ d_cfg->charset = apr_pstrdup(cmd->pool, &w[8]);
+ }
+ else if (!strcasecmp(w, "UseOldDateFormat")) {
+ d_cfg->datetime_format = "%d-%b-%Y %H:%M";
+ }
+ else {
+ return "Invalid directory indexing option";
+ }
+ if (action == '\0') {
+ opts |= option;
+ opts_add = 0;
+ opts_remove = 0;
+ }
+ else if (action == '+') {
+ opts_add |= option;
+ opts_remove &= ~option;
+ }
+ else {
+ opts_remove |= option;
+ opts_add &= ~option;
+ }
+ }
+ if ((opts & NO_OPTIONS) && (opts & ~NO_OPTIONS)) {
+ return "Cannot combine other IndexOptions keywords with 'None'";
+ }
+ d_cfg->incremented_opts = opts_add;
+ d_cfg->decremented_opts = opts_remove;
+ d_cfg->opts = opts;
+ return NULL;
+}
+
+static const char *set_default_order(cmd_parms *cmd, void *m,
+ const char *direction, const char *key)
+{
+ autoindex_config_rec *d_cfg = (autoindex_config_rec *) m;
+
+ if (!strcasecmp(direction, "Ascending")) {
+ d_cfg->default_direction = D_ASCENDING;
+ }
+ else if (!strcasecmp(direction, "Descending")) {
+ d_cfg->default_direction = D_DESCENDING;
+ }
+ else {
+ return "First keyword must be 'Ascending' or 'Descending'";
+ }
+
+ if (!strcasecmp(key, "Name")) {
+ d_cfg->default_keyid = K_NAME;
+ }
+ else if (!strcasecmp(key, "Date")) {
+ d_cfg->default_keyid = K_LAST_MOD;
+ }
+ else if (!strcasecmp(key, "Size")) {
+ d_cfg->default_keyid = K_SIZE;
+ }
+ else if (!strcasecmp(key, "Description")) {
+ d_cfg->default_keyid = K_DESC;
+ }
+ else {
+ return "Second keyword must be 'Name', 'Date', 'Size', or "
+ "'Description'";
+ }
+
+ return NULL;
+}
+
+#define DIR_CMD_PERMS OR_INDEXES
+
+static const command_rec autoindex_cmds[] =
+{
+ AP_INIT_ITERATE2("AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS,
+ "an icon URL followed by one or more filenames"),
+ AP_INIT_ITERATE2("AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS,
+ "an icon URL followed by one or more MIME types"),
+ AP_INIT_ITERATE2("AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS,
+ "an icon URL followed by one or more content encodings"),
+ AP_INIT_ITERATE2("AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS,
+ "alternate descriptive text followed by one or more "
+ "filenames"),
+ AP_INIT_ITERATE2("AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS,
+ "alternate descriptive text followed by one or more MIME "
+ "types"),
+ AP_INIT_ITERATE2("AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS,
+ "alternate descriptive text followed by one or more "
+ "content encodings"),
+ AP_INIT_TAKE_ARGV("IndexOptions", add_opts, NULL, DIR_CMD_PERMS,
+ "one or more index options [+|-][]"),
+ AP_INIT_TAKE2("IndexOrderDefault", set_default_order, NULL, DIR_CMD_PERMS,
+ "{Ascending,Descending} {Name,Size,Description,Date}"),
+ AP_INIT_ITERATE("IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS,
+ "one or more file extensions"),
+ AP_INIT_FLAG("IndexIgnoreReset", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(autoindex_config_rec, ign_noinherit),
+ DIR_CMD_PERMS,
+ "Reset the inherited list of IndexIgnore filenames"),
+ AP_INIT_ITERATE2("AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS,
+ "Descriptive text followed by one or more filenames"),
+ AP_INIT_TAKE1("HeaderName", ap_set_string_slot,
+ (void *)APR_OFFSETOF(autoindex_config_rec, header),
+ DIR_CMD_PERMS, "a filename"),
+ AP_INIT_TAKE1("ReadmeName", ap_set_string_slot,
+ (void *)APR_OFFSETOF(autoindex_config_rec, readme),
+ DIR_CMD_PERMS, "a filename"),
+ AP_INIT_RAW_ARGS("FancyIndexing", ap_set_deprecated, NULL, OR_ALL,
+ "The FancyIndexing directive is no longer supported. "
+ "Use IndexOptions FancyIndexing."),
+ AP_INIT_TAKE1("DefaultIcon", ap_set_string_slot,
+ (void *)APR_OFFSETOF(autoindex_config_rec, default_icon),
+ DIR_CMD_PERMS, "an icon URL"),
+ AP_INIT_TAKE1("IndexStyleSheet", ap_set_string_slot,
+ (void *)APR_OFFSETOF(autoindex_config_rec, style_sheet),
+ DIR_CMD_PERMS, "URL to style sheet"),
+ AP_INIT_TAKE1("IndexHeadInsert", ap_set_string_slot,
+ (void *)APR_OFFSETOF(autoindex_config_rec, head_insert),
+ DIR_CMD_PERMS, "String to insert in HTML HEAD section"),
+ {NULL}
+};
+
+static void *create_autoindex_config(apr_pool_t *p, char *dummy)
+{
+ autoindex_config_rec *new =
+ (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec));
+
+ new->icon_width = 0;
+ new->icon_height = 0;
+ new->name_width = DEFAULT_NAME_WIDTH;
+ new->name_adjust = K_UNSET;
+ new->desc_width = DEFAULT_DESC_WIDTH;
+ new->desc_adjust = K_UNSET;
+ new->icon_list = apr_array_make(p, 4, sizeof(struct item));
+ new->alt_list = apr_array_make(p, 4, sizeof(struct item));
+ new->desc_list = apr_array_make(p, 4, sizeof(ai_desc_t));
+ new->ign_list = apr_array_make(p, 4, sizeof(struct item));
+ new->opts = OPTION_UNSET;
+ new->incremented_opts = 0;
+ new->decremented_opts = 0;
+ new->default_keyid = '\0';
+ new->default_direction = '\0';
+
+ return (void *) new;
+}
+
+static void *merge_autoindex_configs(apr_pool_t *p, void *basev, void *addv)
+{
+ autoindex_config_rec *new;
+ autoindex_config_rec *base = (autoindex_config_rec *) basev;
+ autoindex_config_rec *add = (autoindex_config_rec *) addv;
+
+ new = (autoindex_config_rec *) apr_pcalloc(p, sizeof(autoindex_config_rec));
+ new->default_icon = add->default_icon ? add->default_icon
+ : base->default_icon;
+ new->style_sheet = add->style_sheet ? add->style_sheet
+ : base->style_sheet;
+ new->head_insert = add->head_insert ? add->head_insert
+ : base->head_insert;
+ new->header = add->header ? add->header
+ : base->header;
+ new->readme = add->readme ? add->readme
+ : base->readme;
+ new->icon_height = add->icon_height ? add->icon_height : base->icon_height;
+ new->icon_width = add->icon_width ? add->icon_width : base->icon_width;
+
+ new->ctype = add->ctype ? add->ctype : base->ctype;
+ new->charset = add->charset ? add->charset : base->charset;
+ new->datetime_format = add->datetime_format ? add->datetime_format : base->datetime_format;
+
+ new->alt_list = apr_array_append(p, add->alt_list, base->alt_list);
+ new->desc_list = apr_array_append(p, add->desc_list, base->desc_list);
+ new->icon_list = apr_array_append(p, add->icon_list, base->icon_list);
+ new->ign_list = add->ign_noinherit ? add->ign_list : apr_array_append(p, add->ign_list, base->ign_list);
+ if (add->opts == NO_OPTIONS) {
+ /*
+ * If the current directory explicitly says 'no options' then we also
+ * clear any incremental mods from being inheritable further down.
+ */
+ new->opts = NO_OPTIONS;
+ new->incremented_opts = 0;
+ new->decremented_opts = 0;
+ }
+ else {
+ /*
+ * If there were any nonincremental options selected for
+ * this directory, they dominate and we don't inherit *anything.*
+ * Contrariwise, we *do* inherit if the only settings here are
+ * incremental ones.
+ */
+ if (add->opts == OPTION_UNSET) {
+ new->incremented_opts = (base->incremented_opts
+ | add->incremented_opts)
+ & ~add->decremented_opts;
+ new->decremented_opts = (base->decremented_opts
+ | add->decremented_opts);
+ /*
+ * We may have incremental settings, so make sure we don't
+ * inadvertently inherit an IndexOptions None from above.
+ */
+ new->opts = (base->opts & ~NO_OPTIONS);
+ }
+ else {
+ /*
+ * There are local nonincremental settings, which clear
+ * all inheritance from above. They *are* the new base settings.
+ */
+ new->opts = add->opts;
+ }
+ /*
+ * We're guaranteed that there'll be no overlap between
+ * the add-options and the remove-options.
+ */
+ new->opts |= new->incremented_opts;
+ new->opts &= ~new->decremented_opts;
+ }
+ /*
+ * Inherit the NameWidth settings if there aren't any specific to
+ * the new location; otherwise we'll end up using the defaults set in the
+ * config-rec creation routine.
+ */
+ if (add->name_adjust == K_UNSET) {
+ new->name_width = base->name_width;
+ new->name_adjust = base->name_adjust;
+ }
+ else {
+ new->name_width = add->name_width;
+ new->name_adjust = add->name_adjust;
+ }
+
+ /*
+ * Likewise for DescriptionWidth.
+ */
+ if (add->desc_adjust == K_UNSET) {
+ new->desc_width = base->desc_width;
+ new->desc_adjust = base->desc_adjust;
+ }
+ else {
+ new->desc_width = add->desc_width;
+ new->desc_adjust = add->desc_adjust;
+ }
+
+ new->default_keyid = add->default_keyid ? add->default_keyid
+ : base->default_keyid;
+ new->default_direction = add->default_direction ? add->default_direction
+ : base->default_direction;
+ return new;
+}
+
+/****************************************************************
+ *
+ * Looking things up in config entries...
+ */
+
+/* Structure used to hold entries when we're actually building an index */
+
+struct ent {
+ char *name;
+ char *icon;
+ char *alt;
+ char *desc;
+ apr_off_t size;
+ apr_time_t lm;
+ struct ent *next;
+ int ascending, ignore_case, version_sort;
+ char key;
+ int isdir;
+};
+
+static char *find_item(const char *content_type, const char *content_encoding,
+ char *path, apr_array_header_t *list, int path_only)
+{
+ struct item *items = (struct item *) list->elts;
+ int i;
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+
+ /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
+ if ((path[0] == '^') || (!ap_strcmp_match(path, p->apply_path))) {
+ if (!*(p->apply_to)) {
+ return p->data;
+ }
+ else if (p->type == BY_PATH || path[0] == '^') {
+ if (!ap_strcmp_match(path, p->apply_to)) {
+ return p->data;
+ }
+ }
+ else if (!path_only) {
+ if (!content_encoding) {
+ if (p->type == BY_TYPE) {
+ if (content_type
+ && !ap_strcasecmp_match(content_type,
+ p->apply_to)) {
+ return p->data;
+ }
+ }
+ }
+ else {
+ if (p->type == BY_ENCODING) {
+ if (!ap_strcasecmp_match(content_encoding,
+ p->apply_to)) {
+ return p->data;
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static char *find_item_by_request(request_rec *r, apr_array_header_t *list, int path_only)
+{
+ return find_item(ap_field_noparam(r->pool, r->content_type),
+ r->content_encoding, r->filename, list, path_only);
+}
+
+#define find_icon(d,p,t) find_item_by_request(p,d->icon_list,t)
+#define find_alt(d,p,t) find_item_by_request(p,d->alt_list,t)
+#define find_default_icon(d,n) find_item(NULL, NULL, n, d->icon_list, 1)
+#define find_default_alt(d,n) find_item(NULL, NULL, n, d->alt_list, 1)
+
+/*
+ * Look through the list of pattern/description pairs and return the first one
+ * if any) that matches the filename in the request. If multiple patterns
+ * match, only the first one is used; since the order in the array is the
+ * same as the order in which directives were processed, earlier matching
+ * directives will dominate.
+ */
+
+#ifdef CASE_BLIND_FILESYSTEM
+#define MATCH_FLAGS APR_FNM_CASE_BLIND
+#else
+#define MATCH_FLAGS 0
+#endif
+
+static char *find_desc(autoindex_config_rec *dcfg, const char *filename_full)
+{
+ int i;
+ ai_desc_t *list = (ai_desc_t *) dcfg->desc_list->elts;
+ const char *filename_only;
+ const char *filename;
+
+ /*
+ * If the filename includes a path, extract just the name itself
+ * for the simple matches.
+ */
+ if ((filename_only = ap_strrchr_c(filename_full, '/')) == NULL) {
+ filename_only = filename_full;
+ }
+ else {
+ filename_only++;
+ }
+ for (i = 0; i < dcfg->desc_list->nelts; ++i) {
+ ai_desc_t *tuple = &list[i];
+ int found;
+
+ /*
+ * Only use the full-path filename if the pattern contains '/'s.
+ */
+ filename = (tuple->full_path) ? filename_full : filename_only;
+ /*
+ * Make the comparison using the cheapest method; only do
+ * wildcard checking if we must.
+ */
+ if (tuple->wildcards) {
+ found = (apr_fnmatch(tuple->pattern, filename, MATCH_FLAGS) == 0);
+ }
+ else {
+ found = (ap_strstr_c(filename, tuple->pattern) != NULL);
+ }
+ if (found) {
+ return tuple->description;
+ }
+ }
+ return NULL;
+}
+
+static int ignore_entry(autoindex_config_rec *d, char *path)
+{
+ apr_array_header_t *list = d->ign_list;
+ struct item *items = (struct item *) list->elts;
+ char *tt;
+ int i;
+
+ if ((tt = strrchr(path, '/')) == NULL) {
+ tt = path;
+ }
+ else {
+ tt++;
+ }
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+ char *ap;
+
+ if ((ap = strrchr(p->apply_to, '/')) == NULL) {
+ ap = p->apply_to;
+ }
+ else {
+ ap++;
+ }
+
+#ifndef CASE_BLIND_FILESYSTEM
+ if (!ap_strcmp_match(path, p->apply_path)
+ && !ap_strcmp_match(tt, ap)) {
+ return 1;
+ }
+#else /* !CASE_BLIND_FILESYSTEM */
+ /*
+ * On some platforms, the match must be case-blind. This is really
+ * a factor of the filesystem involved, but we can't detect that
+ * reliably - so we have to granularise at the OS level.
+ */
+ if (!ap_strcasecmp_match(path, p->apply_path)
+ && !ap_strcasecmp_match(tt, ap)) {
+ return 1;
+ }
+#endif /* !CASE_BLIND_FILESYSTEM */
+ }
+ return 0;
+}
+
+/*****************************************************************
+ *
+ * Actually generating output
+ */
+
+/*
+ * Elements of the emitted document:
+ * Preamble
+ * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req
+ * succeeds for the (content_type == text/html) header file.
+ * Header file
+ * Emitted if found (and able).
+ * H1 tag line
+ * Emitted if a header file is NOT emitted.
+ * Directory stuff
+ * Always emitted.
+ * HR
+ * Emitted if FANCY_INDEXING is set.
+ * Readme file
+ * Emitted if found (and able).
+ * ServerSig
+ * Emitted if ServerSignature is not Off AND a readme file
+ * is NOT emitted.
+ * Postamble
+ * Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req
+ * succeeds for the (content_type == text/html) readme file.
+ */
+
+
+/*
+ * emit a plain text file
+ */
+static void do_emit_plain(request_rec *r, apr_file_t *f)
+{
+ char buf[AP_IOBUFSIZE + 1];
+ int ch;
+ apr_size_t i, c, n;
+ apr_status_t rv;
+
+ ap_rputs("<pre>\n", r);
+ while (!apr_file_eof(f)) {
+ do {
+ n = sizeof(char) * AP_IOBUFSIZE;
+ rv = apr_file_read(f, buf, &n);
+ } while (APR_STATUS_IS_EINTR(rv));
+ if (n == 0 || rv != APR_SUCCESS) {
+ /* ###: better error here? */
+ break;
+ }
+ buf[n] = '\0';
+ c = 0;
+ while (c < n) {
+ for (i = c; i < n; i++) {
+ if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') {
+ break;
+ }
+ }
+ ch = buf[i];
+ buf[i] = '\0';
+ ap_rputs(&buf[c], r);
+ if (ch == '<') {
+ ap_rputs("&lt;", r);
+ }
+ else if (ch == '>') {
+ ap_rputs("&gt;", r);
+ }
+ else if (ch == '&') {
+ ap_rputs("&amp;", r);
+ }
+ c = i + 1;
+ }
+ }
+ ap_rputs("</pre>\n", r);
+}
+
+/*
+ * Handle the preamble through the H1 tag line, inclusive. Locate
+ * the file with a subrequests. Process text/html documents by actually
+ * running the subrequest; text/xxx documents get copied verbatim,
+ * and any other content type is ignored. This means that a non-text
+ * document (such as HEADER.gif) might get multiviewed as the result
+ * instead of a text document, meaning nothing will be displayed, but
+ * oh well.
+ */
+static void emit_head(request_rec *r, char *header_fname, int suppress_amble,
+ int emit_xhtml, char *title)
+{
+ autoindex_config_rec *d;
+ apr_table_t *hdrs = r->headers_in;
+ apr_file_t *f = NULL;
+ request_rec *rr = NULL;
+ int emit_amble = 1;
+ int emit_H1 = 1;
+ const char *r_accept;
+ const char *r_accept_enc;
+
+ /*
+ * If there's a header file, send a subrequest to look for it. If it's
+ * found and html do the subrequest, otherwise handle it
+ */
+ r_accept = apr_table_get(hdrs, "Accept");
+ r_accept_enc = apr_table_get(hdrs, "Accept-Encoding");
+ apr_table_setn(hdrs, "Accept", "text/html, text/plain");
+ apr_table_unset(hdrs, "Accept-Encoding");
+
+
+ if ((header_fname != NULL) && r->args) {
+ header_fname = apr_pstrcat(r->pool, header_fname, "?", r->args, NULL);
+ }
+
+ if ((header_fname != NULL)
+ && (rr = ap_sub_req_lookup_uri(header_fname, r, r->output_filters))
+ && (rr->status == HTTP_OK)
+ && (rr->filename != NULL)
+ && (rr->finfo.filetype == APR_REG)) {
+ /*
+ * Check for the two specific cases we allow: text/html and
+ * text/anything-else. The former is allowed to be processed for
+ * SSIs.
+ */
+ if (rr->content_type != NULL) {
+ if (response_is_html(rr)) {
+ ap_filter_t *f;
+ /* Hope everything will work... */
+ emit_amble = 0;
+ emit_H1 = 0;
+
+ if (! suppress_amble) {
+ emit_preamble(r, emit_xhtml, title);
+ }
+ /* This is a hack, but I can't find any better way to do this.
+ * The problem is that we have already created the sub-request,
+ * but we just inserted the OLD_WRITE filter, and the
+ * sub-request needs to pass its data through the OLD_WRITE
+ * filter, or things go horribly wrong (missing data, data in
+ * the wrong order, etc). To fix it, if you create a
+ * sub-request and then insert the OLD_WRITE filter before you
+ * run the request, you need to make sure that the sub-request
+ * data goes through the OLD_WRITE filter. Just steal this
+ * code. The long-term solution is to remove the ap_r*
+ * functions.
+ */
+ for (f=rr->output_filters;
+ f->frec != ap_subreq_core_filter_handle; f = f->next);
+ f->next = r->output_filters;
+
+ /*
+ * If there's a problem running the subrequest, display the
+ * preamble if we didn't do it before -- the header file
+ * didn't get displayed.
+ */
+ if (ap_run_sub_req(rr) != OK) {
+ /* It didn't work */
+ emit_amble = suppress_amble;
+ emit_H1 = 1;
+ }
+ }
+ else if (!strncasecmp("text/", rr->content_type, 5)) {
+ /*
+ * If we can open the file, prefix it with the preamble
+ * regardless; since we'll be sending a <pre> block around
+ * the file's contents, any HTML header it had won't end up
+ * where it belongs.
+ */
+ if (apr_file_open(&f, rr->filename, APR_READ,
+ APR_OS_DEFAULT, r->pool) == APR_SUCCESS) {
+ emit_preamble(r, emit_xhtml, title);
+ emit_amble = 0;
+ do_emit_plain(r, f);
+ apr_file_close(f);
+ emit_H1 = 0;
+ }
+ }
+ }
+ }
+
+ if (r_accept) {
+ apr_table_setn(hdrs, "Accept", r_accept);
+ }
+ else {
+ apr_table_unset(hdrs, "Accept");
+ }
+
+ if (r_accept_enc) {
+ apr_table_setn(hdrs, "Accept-Encoding", r_accept_enc);
+ }
+
+ if (emit_amble) {
+ emit_preamble(r, emit_xhtml, title);
+ }
+
+ d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config, &autoindex_module);
+
+ if (emit_H1) {
+ if (d->style_sheet != NULL) {
+ /* Insert style id if stylesheet used */
+ ap_rvputs(r, " <h1 id=\"indextitle\">Index of ", title, "</h1>\n", NULL);
+ } else {
+ ap_rvputs(r, "<h1>Index of ", title, "</h1>\n", NULL);
+ }
+ }
+ if (rr != NULL) {
+ ap_destroy_sub_req(rr);
+ }
+}
+
+
+/*
+ * Handle the Readme file through the postamble, inclusive. Locate
+ * the file with a subrequests. Process text/html documents by actually
+ * running the subrequest; text/xxx documents get copied verbatim,
+ * and any other content type is ignored. This means that a non-text
+ * document (such as FOOTER.gif) might get multiviewed as the result
+ * instead of a text document, meaning nothing will be displayed, but
+ * oh well.
+ */
+static void emit_tail(request_rec *r, char *readme_fname, int suppress_amble)
+{
+ apr_file_t *f = NULL;
+ request_rec *rr = NULL;
+ int suppress_post = 0;
+ int suppress_sig = 0;
+
+ /*
+ * If there's a readme file, send a subrequest to look for it. If it's
+ * found and a text file, handle it -- otherwise fall through and
+ * pretend there's nothing there.
+ */
+ if ((readme_fname != NULL)
+ && (rr = ap_sub_req_lookup_uri(readme_fname, r, r->output_filters))
+ && (rr->status == HTTP_OK)
+ && (rr->filename != NULL)
+ && rr->finfo.filetype == APR_REG) {
+ /*
+ * Check for the two specific cases we allow: text/html and
+ * text/anything-else. The former is allowed to be processed for
+ * SSIs.
+ */
+ if (rr->content_type != NULL) {
+ if (response_is_html(rr)) {
+ ap_filter_t *f;
+ for (f=rr->output_filters;
+ f->frec != ap_subreq_core_filter_handle; f = f->next);
+ f->next = r->output_filters;
+
+
+ if (ap_run_sub_req(rr) == OK) {
+ /* worked... */
+ suppress_sig = 1;
+ suppress_post = suppress_amble;
+ }
+ }
+ else if (!strncasecmp("text/", rr->content_type, 5)) {
+ /*
+ * If we can open the file, suppress the signature.
+ */
+ if (apr_file_open(&f, rr->filename, APR_READ,
+ APR_OS_DEFAULT, r->pool) == APR_SUCCESS) {
+ do_emit_plain(r, f);
+ apr_file_close(f);
+ suppress_sig = 1;
+ }
+ }
+ }
+ }
+
+ if (!suppress_sig) {
+ ap_rputs(ap_psignature("", r), r);
+ }
+ if (!suppress_post) {
+ ap_rputs("</body></html>\n", r);
+ }
+ if (rr != NULL) {
+ ap_destroy_sub_req(rr);
+ }
+}
+
+
+static char *find_title(request_rec *r)
+{
+ char titlebuf[MAX_STRING_LEN], *find = "<title>";
+ apr_file_t *thefile = NULL;
+ int x, y, p;
+ apr_size_t n;
+
+ if (r->status != HTTP_OK) {
+ return NULL;
+ }
+ if ((r->content_type != NULL)
+ && (response_is_html(r)
+ || !strcmp(r->content_type, INCLUDES_MAGIC_TYPE))
+ && !r->content_encoding) {
+ if (apr_file_open(&thefile, r->filename, APR_READ,
+ APR_OS_DEFAULT, r->pool) != APR_SUCCESS) {
+ return NULL;
+ }
+ n = sizeof(char) * (MAX_STRING_LEN - 1);
+ apr_file_read(thefile, titlebuf, &n);
+ if (n == 0) {
+ apr_file_close(thefile);
+ return NULL;
+ }
+ titlebuf[n] = '\0';
+ for (x = 0, p = 0; titlebuf[x]; x++) {
+ if (apr_tolower(titlebuf[x]) == find[p]) {
+ if (!find[++p]) {
+ if ((p = ap_ind(&titlebuf[++x], '<')) != -1) {
+ titlebuf[x + p] = '\0';
+ }
+ /* Scan for line breaks for Tanmoy's secretary */
+ for (y = x; titlebuf[y]; y++) {
+ if ((titlebuf[y] == CR) || (titlebuf[y] == LF)) {
+ if (y == x) {
+ x++;
+ }
+ else {
+ titlebuf[y] = ' ';
+ }
+ }
+ }
+ apr_file_close(thefile);
+ return apr_pstrdup(r->pool, &titlebuf[x]);
+ }
+ }
+ else {
+ p = 0;
+ }
+ }
+ apr_file_close(thefile);
+ }
+ return NULL;
+}
+
+static struct ent *make_parent_entry(apr_int32_t autoindex_opts,
+ autoindex_config_rec *d,
+ request_rec *r, char keyid,
+ char direction)
+{
+ struct ent *p = (struct ent *) apr_pcalloc(r->pool, sizeof(struct ent));
+ char *testpath;
+ /*
+ * p->name is now the true parent URI.
+ * testpath is a crafted lie, so that the syntax '/some/..'
+ * (or simply '..')be used to describe 'up' from '/some/'
+ * when processeing IndexIgnore, and Icon|Alt|Desc configs.
+ */
+
+ /* The output has always been to the parent. Don't make ourself
+ * our own parent (worthless cyclical reference).
+ */
+ if (!(p->name = ap_make_full_path(r->pool, r->uri, "../"))) {
+ return (NULL);
+ }
+ ap_getparents(p->name);
+ if (!*p->name) {
+ return (NULL);
+ }
+
+ /* IndexIgnore has always compared "/thispath/.." */
+ testpath = ap_make_full_path(r->pool, r->filename, "..");
+ if (ignore_entry(d, testpath)) {
+ return (NULL);
+ }
+
+ p->size = -1;
+ p->lm = -1;
+ p->key = apr_toupper(keyid);
+ p->ascending = (apr_toupper(direction) == D_ASCENDING);
+ p->version_sort = autoindex_opts & VERSION_SORT;
+ if (autoindex_opts & FANCY_INDEXING) {
+ if (!(p->icon = find_default_icon(d, testpath))) {
+ p->icon = find_default_icon(d, "^^DIRECTORY^^");
+ }
+ if (!(p->alt = find_default_alt(d, testpath))) {
+ if (!(p->alt = find_default_alt(d, "^^DIRECTORY^^"))) {
+ /* Special alt text for parent dir to distinguish it from other directories
+ this is essential when trying to style this dir entry via AddAltClass */
+ p->alt = "PARENTDIR";
+ }
+ }
+ p->desc = find_desc(d, testpath);
+ }
+ return p;
+}
+
+static struct ent *make_autoindex_entry(const apr_finfo_t *dirent,
+ int autoindex_opts,
+ autoindex_config_rec *d,
+ request_rec *r, char keyid,
+ char direction,
+ const char *pattern)
+{
+ request_rec *rr;
+ struct ent *p;
+ int show_forbidden = 0;
+
+ /* Dot is ignored, Parent is handled by make_parent_entry() */
+ if ((dirent->name[0] == '.') && (!dirent->name[1]
+ || ((dirent->name[1] == '.') && !dirent->name[2])))
+ return (NULL);
+
+ /*
+ * On some platforms, the match must be case-blind. This is really
+ * a factor of the filesystem involved, but we can't detect that
+ * reliably - so we have to granularise at the OS level.
+ */
+ if (pattern && (apr_fnmatch(pattern, dirent->name,
+ APR_FNM_NOESCAPE | APR_FNM_PERIOD
+#ifdef CASE_BLIND_FILESYSTEM
+ | APR_FNM_CASE_BLIND
+#endif
+ )
+ != APR_SUCCESS)) {
+ return (NULL);
+ }
+
+ if (ignore_entry(d, ap_make_full_path(r->pool,
+ r->filename, dirent->name))) {
+ return (NULL);
+ }
+
+ if (!(rr = ap_sub_req_lookup_dirent(dirent, r, AP_SUBREQ_NO_ARGS, NULL))) {
+ return (NULL);
+ }
+
+ if ((autoindex_opts & SHOW_FORBIDDEN)
+ && (rr->status == HTTP_UNAUTHORIZED || rr->status == HTTP_FORBIDDEN)) {
+ show_forbidden = 1;
+ }
+
+ if ((rr->finfo.filetype != APR_DIR && rr->finfo.filetype != APR_REG)
+ || !(rr->status == OK || ap_is_HTTP_SUCCESS(rr->status)
+ || ap_is_HTTP_REDIRECT(rr->status)
+ || show_forbidden == 1)) {
+ ap_destroy_sub_req(rr);
+ return (NULL);
+ }
+
+ p = (struct ent *) apr_pcalloc(r->pool, sizeof(struct ent));
+ if (dirent->filetype == APR_DIR) {
+ p->name = apr_pstrcat(r->pool, dirent->name, "/", NULL);
+ }
+ else {
+ p->name = apr_pstrdup(r->pool, dirent->name);
+ }
+ p->size = -1;
+ p->icon = NULL;
+ p->alt = NULL;
+ p->desc = NULL;
+ p->lm = -1;
+ p->isdir = 0;
+ p->key = apr_toupper(keyid);
+ p->ascending = (apr_toupper(direction) == D_ASCENDING);
+ p->version_sort = !!(autoindex_opts & VERSION_SORT);
+ p->ignore_case = !!(autoindex_opts & IGNORE_CASE);
+
+ if (autoindex_opts & (FANCY_INDEXING | TABLE_INDEXING)) {
+ p->lm = rr->finfo.mtime;
+ if (dirent->filetype == APR_DIR) {
+ if (autoindex_opts & FOLDERS_FIRST) {
+ p->isdir = 1;
+ }
+ rr->filename = ap_make_dirstr_parent (rr->pool, rr->filename);
+
+ /* omit the trailing slash (1.3 compat) */
+ rr->filename[strlen(rr->filename) - 1] = '\0';
+
+ if (!(p->icon = find_icon(d, rr, 1))) {
+ p->icon = find_default_icon(d, "^^DIRECTORY^^");
+ }
+ if (!(p->alt = find_alt(d, rr, 1))) {
+ if (!(p->alt = find_default_alt(d, "^^DIRECTORY^^"))) {
+ p->alt = "DIR";
+ }
+ }
+ }
+ else {
+ p->icon = find_icon(d, rr, 0);
+ p->alt = find_alt(d, rr, 0);
+ p->size = rr->finfo.size;
+ }
+
+ p->desc = find_desc(d, rr->filename);
+
+ if ((!p->desc) && (autoindex_opts & SCAN_HTML_TITLES)) {
+ p->desc = apr_pstrdup(r->pool, find_title(rr));
+ }
+ }
+ ap_destroy_sub_req(rr);
+ /*
+ * We don't need to take any special action for the file size key.
+ * If we did, it would go here.
+ */
+ if (keyid == K_LAST_MOD) {
+ if (p->lm < 0) {
+ p->lm = 0;
+ }
+ }
+ return (p);
+}
+
+static char *terminate_description(autoindex_config_rec *d, char *desc,
+ apr_int32_t autoindex_opts, int desc_width)
+{
+ int maxsize = desc_width;
+ int x;
+
+ /*
+ * If there's no DescriptionWidth in effect, default to the old
+ * behaviour of adjusting the description size depending upon
+ * what else is being displayed. Otherwise, stick with the
+ * setting.
+ */
+ if (d->desc_adjust == K_UNSET) {
+ if (autoindex_opts & SUPPRESS_ICON) {
+ maxsize += 6;
+ }
+ if (autoindex_opts & SUPPRESS_LAST_MOD) {
+ maxsize += 19;
+ }
+ if (autoindex_opts & SUPPRESS_SIZE) {
+ maxsize += 7;
+ }
+ }
+ for (x = 0; desc[x] && ((maxsize > 0) || (desc[x] == '<')); x++) {
+ if (desc[x] == '<') {
+ while (desc[x] != '>') {
+ if (!desc[x]) {
+ maxsize = 0;
+ break;
+ }
+ ++x;
+ }
+ }
+ else if (desc[x] == '&') {
+ /* entities like &auml; count as one character */
+ --maxsize;
+ for ( ; desc[x] != ';'; ++x) {
+ if (desc[x] == '\0') {
+ maxsize = 0;
+ break;
+ }
+ }
+ }
+ else {
+ --maxsize;
+ }
+ }
+ if (!maxsize && desc[x] != '\0') {
+ desc[x - 1] = '>'; /* Grump. */
+ desc[x] = '\0'; /* Double Grump! */
+ }
+ return desc;
+}
+
+/*
+ * Emit the anchor for the specified field. If a field is the key for the
+ * current request, the link changes its meaning to reverse the order when
+ * selected again. Non-active fields always start in ascending order.
+ */
+static void emit_link(request_rec *r, const char *anchor, char column,
+ char curkey, char curdirection,
+ const char *colargs, int nosort)
+{
+ if (!nosort) {
+ char qvalue[9];
+
+ qvalue[0] = '?';
+ qvalue[1] = 'C';
+ qvalue[2] = '=';
+ qvalue[3] = column;
+ qvalue[4] = ';';
+ qvalue[5] = 'O';
+ qvalue[6] = '=';
+ /* reverse? */
+ qvalue[7] = ((curkey == column) && (curdirection == D_ASCENDING))
+ ? D_DESCENDING : D_ASCENDING;
+ qvalue[8] = '\0';
+ ap_rvputs(r, "<a href=\"", qvalue, colargs ? colargs : "",
+ "\">", anchor, "</a>", NULL);
+ }
+ else {
+ ap_rputs(anchor, r);
+ }
+}
+
+static void output_directories(struct ent **ar, int n,
+ autoindex_config_rec *d, request_rec *r,
+ apr_int32_t autoindex_opts, char keyid,
+ char direction, const char *colargs)
+{
+ int x;
+ apr_size_t rv;
+ char *tp;
+ int static_columns = !!(autoindex_opts & SUPPRESS_COLSORT);
+ apr_pool_t *scratch;
+ int name_width;
+ int desc_width;
+ char *datetime_format;
+ char *name_scratch;
+ char *pad_scratch;
+ char *breakrow = "";
+
+ apr_pool_create(&scratch, r->pool);
+
+ name_width = d->name_width;
+ desc_width = d->desc_width;
+ datetime_format = d->datetime_format ? d->datetime_format : "%Y-%m-%d %H:%M";
+
+ if ((autoindex_opts & (FANCY_INDEXING | TABLE_INDEXING))
+ == FANCY_INDEXING) {
+ if (d->name_adjust == K_ADJUST) {
+ for (x = 0; x < n; x++) {
+ int t = strlen(ar[x]->name);
+ if (t > name_width) {
+ name_width = t;
+ }
+ }
+ }
+
+ if (d->desc_adjust == K_ADJUST) {
+ for (x = 0; x < n; x++) {
+ if (ar[x]->desc != NULL) {
+ int t = strlen(ar[x]->desc);
+ if (t > desc_width) {
+ desc_width = t;
+ }
+ }
+ }
+ }
+ }
+ name_scratch = apr_palloc(r->pool, name_width + 1);
+ pad_scratch = apr_palloc(r->pool, name_width + 1);
+ memset(pad_scratch, ' ', name_width);
+ pad_scratch[name_width] = '\0';
+
+ if (autoindex_opts & TABLE_INDEXING) {
+ int cols = 1;
+ if (d->style_sheet != NULL) {
+ /* Emit table with style id */
+ ap_rputs(" <table id=\"indexlist\">\n <tr class=\"indexhead\">", r);
+ } else {
+ ap_rputs(" <table>\n <tr>", r);
+ }
+ if (!(autoindex_opts & SUPPRESS_ICON)) {
+ ap_rvputs(r, "<th", (d->style_sheet != NULL) ? " class=\"indexcolicon\">" : " valign=\"top\">", NULL);
+ if ((tp = find_default_icon(d, "^^BLANKICON^^"))) {
+ ap_rvputs(r, "<img src=\"", ap_escape_html(scratch, tp),
+ "\" alt=\"[ICO]\"", NULL);
+ if (d->icon_width) {
+ ap_rprintf(r, " width=\"%d\"", d->icon_width);
+ }
+ if (d->icon_height) {
+ ap_rprintf(r, " height=\"%d\"", d->icon_height);
+ }
+
+ if (autoindex_opts & EMIT_XHTML) {
+ ap_rputs(" /", r);
+ }
+ ap_rputs("></th>", r);
+ }
+ else {
+ ap_rputs("&nbsp;</th>", r);
+ }
+
+ ++cols;
+ }
+ ap_rvputs(r, "<th", (d->style_sheet != NULL) ? " class=\"indexcolname\">" : ">", NULL);
+ emit_link(r, "Name", K_NAME, keyid, direction,
+ colargs, static_columns);
+ if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
+ ap_rvputs(r, "</th><th", (d->style_sheet != NULL) ? " class=\"indexcollastmod\">" : ">", NULL);
+ emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
+ colargs, static_columns);
+ ++cols;
+ }
+ if (!(autoindex_opts & SUPPRESS_SIZE)) {
+ ap_rvputs(r, "</th><th", (d->style_sheet != NULL) ? " class=\"indexcolsize\">" : ">", NULL);
+ emit_link(r, "Size", K_SIZE, keyid, direction,
+ colargs, static_columns);
+ ++cols;
+ }
+ if (!(autoindex_opts & SUPPRESS_DESC)) {
+ ap_rvputs(r, "</th><th", (d->style_sheet != NULL) ? " class=\"indexcoldesc\">" : ">", NULL);
+ emit_link(r, "Description", K_DESC, keyid, direction,
+ colargs, static_columns);
+ ++cols;
+ }
+ if (!(autoindex_opts & SUPPRESS_RULES)) {
+ breakrow = apr_psprintf(r->pool,
+ " <tr%s><th colspan=\"%d\">"
+ "<hr%s></th></tr>\n",
+ (d->style_sheet != NULL) ? " class=\"indexbreakrow\"" : "",
+ cols,
+ (autoindex_opts & EMIT_XHTML) ? " /" : "");
+ }
+ ap_rvputs(r, "</th></tr>\n", breakrow, NULL);
+ }
+ else if (autoindex_opts & FANCY_INDEXING) {
+ ap_rputs("<pre>", r);
+ if (!(autoindex_opts & SUPPRESS_ICON)) {
+ if ((tp = find_default_icon(d, "^^BLANKICON^^"))) {
+ ap_rvputs(r, "<img src=\"", ap_escape_html(scratch, tp),
+ "\" alt=\"Icon \"", NULL);
+ if (d->icon_width) {
+ ap_rprintf(r, " width=\"%d\"", d->icon_width);
+ }
+ if (d->icon_height) {
+ ap_rprintf(r, " height=\"%d\"", d->icon_height);
+ }
+
+ if (autoindex_opts & EMIT_XHTML) {
+ ap_rputs(" /", r);
+ }
+ ap_rputs("> ", r);
+ }
+ else {
+ ap_rputs(" ", r);
+ }
+ }
+ emit_link(r, "Name", K_NAME, keyid, direction,
+ colargs, static_columns);
+ ap_rputs(pad_scratch + 4, r);
+ /*
+ * Emit the guaranteed-at-least-one-space-between-columns byte.
+ */
+ ap_rputs(" ", r);
+ if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
+ emit_link(r, "Last modified", K_LAST_MOD, keyid, direction,
+ colargs, static_columns);
+ ap_rputs(" ", r);
+ }
+ if (!(autoindex_opts & SUPPRESS_SIZE)) {
+ emit_link(r, "Size", K_SIZE, keyid, direction,
+ colargs, static_columns);
+ ap_rputs(" ", r);
+ }
+ if (!(autoindex_opts & SUPPRESS_DESC)) {
+ emit_link(r, "Description", K_DESC, keyid, direction,
+ colargs, static_columns);
+ }
+ if (!(autoindex_opts & SUPPRESS_RULES)) {
+ ap_rputs("<hr", r);
+ if (autoindex_opts & EMIT_XHTML) {
+ ap_rputs(" /", r);
+ }
+ ap_rputs(">", r);
+ }
+ else {
+ ap_rputc('\n', r);
+ }
+ }
+ else {
+ ap_rputs("<ul>", r);
+ }
+
+ for (x = 0; x < n; x++) {
+ char *anchor, *t, *t2;
+ int nwidth;
+
+ apr_pool_clear(scratch);
+
+ t = ar[x]->name;
+ anchor = ap_escape_html(scratch, ap_os_escape_path(scratch, t, 0));
+
+ if (!x && t[0] == '/') {
+ t2 = "Parent Directory";
+ }
+ else {
+ t2 = t;
+ }
+
+ if (autoindex_opts & TABLE_INDEXING) {
+ /* Even/Odd rows for IndexStyleSheet */
+ if (d->style_sheet != NULL) {
+ if (ar[x]->alt && (autoindex_opts & ADDALTCLASS)) {
+ /* Include alt text in class name, distinguish between odd and even rows */
+ char *altclass = apr_pstrdup(scratch, ar[x]->alt);
+ ap_str_tolower(altclass);
+ ap_rvputs(r, " <tr class=\"", ( x & 0x1) ? "odd-" : "even-", altclass, "\">", NULL);
+ } else {
+ /* Distinguish between odd and even rows */
+ ap_rvputs(r, " <tr class=\"", ( x & 0x1) ? "odd" : "even", "\">", NULL);
+ }
+ } else {
+ ap_rputs("<tr>", r);
+ }
+
+ if (!(autoindex_opts & SUPPRESS_ICON)) {
+ ap_rvputs(r, "<td", (d->style_sheet != NULL) ? " class=\"indexcolicon\">" : " valign=\"top\">", NULL);
+ if (autoindex_opts & ICONS_ARE_LINKS) {
+ ap_rvputs(r, "<a href=\"", anchor, "\">", NULL);
+ }
+ if ((ar[x]->icon) || d->default_icon) {
+ ap_rvputs(r, "<img src=\"",
+ ap_escape_html(scratch,
+ ar[x]->icon ? ar[x]->icon
+ : d->default_icon),
+ "\" alt=\"[", (ar[x]->alt ? ar[x]->alt : " "),
+ "]\"", NULL);
+ if (d->icon_width) {
+ ap_rprintf(r, " width=\"%d\"", d->icon_width);
+ }
+ if (d->icon_height) {
+ ap_rprintf(r, " height=\"%d\"", d->icon_height);
+ }
+
+ if (autoindex_opts & EMIT_XHTML) {
+ ap_rputs(" /", r);
+ }
+ ap_rputs(">", r);
+ }
+ else {
+ ap_rputs("&nbsp;", r);
+ }
+ if (autoindex_opts & ICONS_ARE_LINKS) {
+ ap_rputs("</a></td>", r);
+ }
+ else {
+ ap_rputs("</td>", r);
+ }
+ }
+ if (d->name_adjust == K_ADJUST) {
+ ap_rvputs(r, "<td", (d->style_sheet != NULL) ? " class=\"indexcolname\">" : ">", "<a href=\"", anchor, "\">",
+ ap_escape_html(scratch, t2), "</a>", NULL);
+ }
+ else {
+ nwidth = strlen(t2);
+ if (nwidth > name_width) {
+ memcpy(name_scratch, t2, name_width - 3);
+ name_scratch[name_width - 3] = '.';
+ name_scratch[name_width - 2] = '.';
+ name_scratch[name_width - 1] = '>';
+ name_scratch[name_width] = 0;
+ t2 = name_scratch;
+ nwidth = name_width;
+ }
+ ap_rvputs(r, "<td", (d->style_sheet != NULL) ? " class=\"indexcolname\">" : ">", "<a href=\"", anchor, "\">",
+ ap_escape_html(scratch, t2),
+ "</a>", pad_scratch + nwidth, NULL);
+ }
+ if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
+ if (ar[x]->lm != -1) {
+ char time_str[32];
+ apr_time_exp_t ts;
+ apr_time_exp_lt(&ts, ar[x]->lm);
+ apr_strftime(time_str, &rv, sizeof(time_str),
+ datetime_format,
+ &ts);
+ ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcollastmod\">" : " align=\"right\">", time_str, " ", NULL);
+ }
+ else {
+ ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcollastmod\">&nbsp;" : ">&nbsp;", NULL);
+ }
+ }
+ if (!(autoindex_opts & SUPPRESS_SIZE)) {
+ char buf[5];
+ ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcolsize\">" : " align=\"right\">",
+ apr_strfsize(ar[x]->size, buf), NULL);
+ }
+ if (!(autoindex_opts & SUPPRESS_DESC)) {
+ if (ar[x]->desc) {
+ if (d->desc_adjust == K_ADJUST) {
+ ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcoldesc\">" : ">", ar[x]->desc, NULL);
+ }
+ else {
+ ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcoldesc\">" : ">",
+ terminate_description(d, ar[x]->desc,
+ autoindex_opts,
+ desc_width), NULL);
+ }
+ }
+ else {
+ ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcoldesc\">" : ">", "&nbsp;", NULL);
+ }
+ }
+ ap_rputs("</td></tr>\n", r);
+ }
+ else if (autoindex_opts & FANCY_INDEXING) {
+ if (!(autoindex_opts & SUPPRESS_ICON)) {
+ if (autoindex_opts & ICONS_ARE_LINKS) {
+ ap_rvputs(r, "<a href=\"", anchor, "\">", NULL);
+ }
+ if ((ar[x]->icon) || d->default_icon) {
+ ap_rvputs(r, "<img src=\"",
+ ap_escape_html(scratch,
+ ar[x]->icon ? ar[x]->icon
+ : d->default_icon),
+ "\" alt=\"[", (ar[x]->alt ? ar[x]->alt : " "),
+ "]\"", NULL);
+ if (d->icon_width) {
+ ap_rprintf(r, " width=\"%d\"", d->icon_width);
+ }
+ if (d->icon_height) {
+ ap_rprintf(r, " height=\"%d\"", d->icon_height);
+ }
+
+ if (autoindex_opts & EMIT_XHTML) {
+ ap_rputs(" /", r);
+ }
+ ap_rputs(">", r);
+ }
+ else {
+ ap_rputs(" ", r);
+ }
+ if (autoindex_opts & ICONS_ARE_LINKS) {
+ ap_rputs("</a> ", r);
+ }
+ else {
+ ap_rputc(' ', r);
+ }
+ }
+ nwidth = strlen(t2);
+ if (nwidth > name_width) {
+ memcpy(name_scratch, t2, name_width - 3);
+ name_scratch[name_width - 3] = '.';
+ name_scratch[name_width - 2] = '.';
+ name_scratch[name_width - 1] = '>';
+ name_scratch[name_width] = 0;
+ t2 = name_scratch;
+ nwidth = name_width;
+ }
+ ap_rvputs(r, "<a href=\"", anchor, "\">",
+ ap_escape_html(scratch, t2),
+ "</a>", pad_scratch + nwidth, NULL);
+ /*
+ * The blank before the storm.. er, before the next field.
+ */
+ ap_rputs(" ", r);
+ if (!(autoindex_opts & SUPPRESS_LAST_MOD)) {
+ if (ar[x]->lm != -1) {
+ char time_str[32];
+ apr_time_exp_t ts;
+ apr_time_exp_lt(&ts, ar[x]->lm);
+ apr_strftime(time_str, &rv, sizeof(time_str),
+ datetime_format,
+ &ts);
+ ap_rvputs(r, time_str, " ", NULL);
+ }
+ else {
+ /* Length="1975-04-07 01:23 " (default in 2.4 and later) or
+ * Length="07-Apr-1975 01:24 ". (2.2 and UseOldDateFormat)
+ * See 'datetime_format' above.
+ */
+ ap_rputs(" ", r);
+ }
+ }
+ if (!(autoindex_opts & SUPPRESS_SIZE)) {
+ char buf[5];
+ ap_rputs(apr_strfsize(ar[x]->size, buf), r);
+ ap_rputs(" ", r);
+ }
+ if (!(autoindex_opts & SUPPRESS_DESC)) {
+ if (ar[x]->desc) {
+ ap_rputs(terminate_description(d, ar[x]->desc,
+ autoindex_opts,
+ desc_width), r);
+ }
+ }
+ ap_rputc('\n', r);
+ }
+ else {
+ ap_rvputs(r, "<li><a href=\"", anchor, "\"> ",
+ ap_escape_html(scratch, t2),
+ "</a></li>\n", NULL);
+ }
+ }
+ if (autoindex_opts & TABLE_INDEXING) {
+ ap_rvputs(r, breakrow, "</table>\n", NULL);
+ }
+ else if (autoindex_opts & FANCY_INDEXING) {
+ if (!(autoindex_opts & SUPPRESS_RULES)) {
+ ap_rputs("<hr", r);
+ if (autoindex_opts & EMIT_XHTML) {
+ ap_rputs(" /", r);
+ }
+ ap_rputs("></pre>\n", r);
+ }
+ else {
+ ap_rputs("</pre>\n", r);
+ }
+ }
+ else {
+ ap_rputs("</ul>\n", r);
+ }
+}
+
+/*
+ * Compare two file entries according to the sort criteria. The return
+ * is essentially a signum function value.
+ */
+
+static int dsortf(struct ent **e1, struct ent **e2)
+{
+ struct ent *c1;
+ struct ent *c2;
+ int result = 0;
+
+ /*
+ * First, see if either of the entries is for the parent directory.
+ * If so, that *always* sorts lower than anything else.
+ */
+ if ((*e1)->name[0] == '/') {
+ return -1;
+ }
+ if ((*e2)->name[0] == '/') {
+ return 1;
+ }
+ /*
+ * Now see if one's a directory and one isn't, if we're set
+ * isdir for FOLDERS_FIRST.
+ */
+ if ((*e1)->isdir != (*e2)->isdir) {
+ return (*e1)->isdir ? -1 : 1;
+ }
+ /*
+ * All of our comparisons will be of the c1 entry against the c2 one,
+ * so assign them appropriately to take care of the ordering.
+ */
+ if ((*e1)->ascending) {
+ c1 = *e1;
+ c2 = *e2;
+ }
+ else {
+ c1 = *e2;
+ c2 = *e1;
+ }
+
+ switch (c1->key) {
+ case K_LAST_MOD:
+ if (c1->lm > c2->lm) {
+ return 1;
+ }
+ else if (c1->lm < c2->lm) {
+ return -1;
+ }
+ break;
+ case K_SIZE:
+ if (c1->size > c2->size) {
+ return 1;
+ }
+ else if (c1->size < c2->size) {
+ return -1;
+ }
+ break;
+ case K_DESC:
+ if (c1->version_sort) {
+ result = apr_strnatcmp(c1->desc ? c1->desc : "",
+ c2->desc ? c2->desc : "");
+ }
+ else {
+ result = strcmp(c1->desc ? c1->desc : "",
+ c2->desc ? c2->desc : "");
+ }
+ if (result) {
+ return result;
+ }
+ break;
+ }
+
+ /* names may identical when treated case-insensitively,
+ * so always fall back on strcmp() flavors to put entries
+ * in deterministic order. This means that 'ABC' and 'abc'
+ * will always appear in the same order, rather than
+ * variably between 'ABC abc' and 'abc ABC' order.
+ */
+
+ if (c1->version_sort) {
+ if (c1->ignore_case) {
+ result = apr_strnatcasecmp (c1->name, c2->name);
+ }
+ if (!result) {
+ result = apr_strnatcmp(c1->name, c2->name);
+ }
+ }
+
+ /* The names may be identical in respects other than
+ * filename case when strnatcmp is used above, so fall back
+ * to strcmp on conflicts so that fn1.01.zzz and fn1.1.zzz
+ * are also sorted in a deterministic order.
+ */
+
+ if (!result && c1->ignore_case) {
+ result = strcasecmp (c1->name, c2->name);
+ }
+
+ if (!result) {
+ result = strcmp (c1->name, c2->name);
+ }
+
+ return result;
+}
+
+
+static int index_directory(request_rec *r,
+ autoindex_config_rec *autoindex_conf)
+{
+ char *title_name = ap_escape_html(r->pool, r->uri);
+ char *title_endp;
+ char *name = r->filename;
+ char *pstring = NULL;
+ apr_finfo_t dirent;
+ apr_dir_t *thedir;
+ apr_status_t status;
+ int num_ent = 0, x;
+ struct ent *head, *p;
+ struct ent **ar = NULL;
+ const char *qstring;
+ apr_int32_t autoindex_opts = autoindex_conf->opts;
+ char keyid;
+ char direction;
+ char *colargs;
+ char *fullpath;
+ apr_size_t dirpathlen;
+ char *ctype = "text/html";
+ char *charset;
+
+ if ((status = apr_dir_open(&thedir, name, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01275)
+ "Can't open directory for index: %s", r->filename);
+ return HTTP_FORBIDDEN;
+ }
+
+ if (autoindex_conf->ctype) {
+ ctype = autoindex_conf->ctype;
+ }
+ if (autoindex_conf->charset) {
+ charset = autoindex_conf->charset;
+ }
+ else {
+#if APR_HAS_UNICODE_FS
+ charset = "UTF-8";
+#else
+ charset = "ISO-8859-1";
+#endif
+ }
+ if (*charset) {
+ ap_set_content_type(r, apr_pstrcat(r->pool, ctype, ";charset=",
+ charset, NULL));
+ }
+ else {
+ ap_set_content_type(r, ctype);
+ }
+
+ if (autoindex_opts & TRACK_MODIFIED) {
+ ap_update_mtime(r, r->finfo.mtime);
+ ap_set_last_modified(r);
+ ap_set_etag(r);
+ }
+ if (r->header_only) {
+ apr_dir_close(thedir);
+ return 0;
+ }
+
+ /*
+ * If there is no specific ordering defined for this directory,
+ * default to ascending by filename.
+ */
+ keyid = autoindex_conf->default_keyid
+ ? autoindex_conf->default_keyid : K_NAME;
+ direction = autoindex_conf->default_direction
+ ? autoindex_conf->default_direction : D_ASCENDING;
+
+ /*
+ * Figure out what sort of indexing (if any) we're supposed to use.
+ *
+ * If no QUERY_STRING was specified or client query strings have been
+ * explicitly disabled.
+ * If we are ignoring the client, suppress column sorting as well.
+ */
+ if (autoindex_opts & IGNORE_CLIENT) {
+ qstring = NULL;
+ autoindex_opts |= SUPPRESS_COLSORT;
+ colargs = "";
+ }
+ else {
+ char fval[5], vval[5], *ppre = "", *epattern = "";
+ fval[0] = '\0'; vval[0] = '\0';
+ qstring = r->args;
+
+ while (qstring && *qstring) {
+
+ /* C= First Sort key Column (N, M, S, D) */
+ if ( qstring[0] == 'C' && qstring[1] == '='
+ && qstring[2] && strchr(K_VALID, qstring[2])
+ && ( qstring[3] == '&' || qstring[3] == ';'
+ || !qstring[3])) {
+ keyid = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+
+ /* O= Sort order (A, D) */
+ else if ( qstring[0] == 'O' && qstring[1] == '='
+ && ( (qstring[2] == D_ASCENDING)
+ || (qstring[2] == D_DESCENDING))
+ && ( qstring[3] == '&' || qstring[3] == ';'
+ || !qstring[3])) {
+ direction = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+
+ /* F= Output Format (0 plain, 1 fancy (pre), 2 table) */
+ else if ( qstring[0] == 'F' && qstring[1] == '='
+ && qstring[2] && strchr("012", qstring[2])
+ && ( qstring[3] == '&' || qstring[3] == ';'
+ || !qstring[3])) {
+ if (qstring[2] == '0') {
+ autoindex_opts &= ~(FANCY_INDEXING | TABLE_INDEXING);
+ }
+ else if (qstring[2] == '1') {
+ autoindex_opts = (autoindex_opts | FANCY_INDEXING)
+ & ~TABLE_INDEXING;
+ }
+ else if (qstring[2] == '2') {
+ autoindex_opts |= FANCY_INDEXING | TABLE_INDEXING;
+ }
+ strcpy(fval, ";F= ");
+ fval[3] = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+
+ /* V= Version sort (0, 1) */
+ else if ( qstring[0] == 'V' && qstring[1] == '='
+ && (qstring[2] == '0' || qstring[2] == '1')
+ && ( qstring[3] == '&' || qstring[3] == ';'
+ || !qstring[3])) {
+ if (qstring[2] == '0') {
+ autoindex_opts &= ~VERSION_SORT;
+ }
+ else if (qstring[2] == '1') {
+ autoindex_opts |= VERSION_SORT;
+ }
+ strcpy(vval, ";V= ");
+ vval[3] = qstring[2];
+ qstring += qstring[3] ? 4 : 3;
+ }
+
+ /* P= wildcard pattern (*.foo) */
+ else if (qstring[0] == 'P' && qstring[1] == '=') {
+ const char *eos = qstring += 2; /* for efficiency */
+
+ while (*eos && *eos != '&' && *eos != ';') {
+ ++eos;
+ }
+
+ if (eos == qstring) {
+ pstring = NULL;
+ }
+ else {
+ pstring = apr_pstrndup(r->pool, qstring, eos - qstring);
+ if (ap_unescape_url(pstring) != OK) {
+ /* ignore the pattern, if it's bad. */
+ pstring = NULL;
+ }
+ else {
+ ppre = ";P=";
+ /* be correct */
+ epattern = ap_escape_uri(r->pool, pstring);
+ }
+ }
+
+ if (*eos && *++eos) {
+ qstring = eos;
+ }
+ else {
+ qstring = NULL;
+ }
+ }
+
+ /* Syntax error? Ignore the remainder! */
+ else {
+ qstring = NULL;
+ }
+ }
+ colargs = apr_pstrcat(r->pool, fval, vval, ppre, epattern, NULL);
+ }
+
+ /* Spew HTML preamble */
+ title_endp = title_name + strlen(title_name) - 1;
+
+ while (title_endp > title_name && *title_endp == '/') {
+ *title_endp-- = '\0';
+ }
+
+ emit_head(r, autoindex_conf->header,
+ autoindex_opts & SUPPRESS_PREAMBLE,
+ autoindex_opts & EMIT_XHTML, title_name);
+
+ /*
+ * Since we don't know how many dir. entries there are, put them into a
+ * linked list and then arrayificate them so qsort can use them.
+ */
+ head = NULL;
+ p = make_parent_entry(autoindex_opts, autoindex_conf, r, keyid, direction);
+ if (p != NULL) {
+ p->next = head;
+ head = p;
+ num_ent++;
+ }
+ fullpath = apr_palloc(r->pool, APR_PATH_MAX);
+ dirpathlen = strlen(name);
+ memcpy(fullpath, name, dirpathlen);
+
+ do {
+ status = apr_dir_read(&dirent, APR_FINFO_MIN | APR_FINFO_NAME, thedir);
+ if (APR_STATUS_IS_INCOMPLETE(status)) {
+ continue; /* ignore un-stat()able files */
+ }
+ else if (status != APR_SUCCESS) {
+ break;
+ }
+
+ /* We want to explode symlinks here. */
+ if (dirent.filetype == APR_LNK) {
+ const char *savename;
+ apr_finfo_t fi;
+ /* We *must* have FNAME. */
+ savename = dirent.name;
+ apr_cpystrn(fullpath + dirpathlen, dirent.name,
+ APR_PATH_MAX - dirpathlen);
+ status = apr_stat(&fi, fullpath,
+ dirent.valid & ~(APR_FINFO_NAME), r->pool);
+ if (status != APR_SUCCESS) {
+ /* Something bad happened, skip this file. */
+ continue;
+ }
+ memcpy(&dirent, &fi, sizeof(fi));
+ dirent.name = savename;
+ dirent.valid |= APR_FINFO_NAME;
+ }
+ p = make_autoindex_entry(&dirent, autoindex_opts, autoindex_conf, r,
+ keyid, direction, pstring);
+ if (p != NULL) {
+ p->next = head;
+ head = p;
+ num_ent++;
+ }
+ } while (1);
+
+ if (num_ent > 0) {
+ ar = (struct ent **) apr_palloc(r->pool,
+ num_ent * sizeof(struct ent *));
+ p = head;
+ x = 0;
+ while (p) {
+ ar[x++] = p;
+ p = p->next;
+ }
+
+ qsort((void *) ar, num_ent, sizeof(struct ent *),
+ (int (*)(const void *, const void *)) dsortf);
+ }
+ output_directories(ar, num_ent, autoindex_conf, r, autoindex_opts,
+ keyid, direction, colargs);
+ apr_dir_close(thedir);
+
+ emit_tail(r, autoindex_conf->readme,
+ autoindex_opts & SUPPRESS_PREAMBLE);
+
+ return 0;
+}
+
+/* The formal handler... */
+
+static int handle_autoindex(request_rec *r)
+{
+ autoindex_config_rec *d;
+ int allow_opts;
+
+ if (strcmp(r->handler,DIR_MAGIC_TYPE) && !AP_IS_DEFAULT_HANDLER_NAME(r->handler)) {
+ return DECLINED;
+ }
+ if (r->finfo.filetype != APR_DIR) {
+ return DECLINED;
+ }
+
+ allow_opts = ap_allow_options(r);
+
+ d = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config,
+ &autoindex_module);
+
+ r->allowed |= (AP_METHOD_BIT << M_GET);
+ if (r->method_number != M_GET) {
+ return DECLINED;
+ }
+
+ /* OK, nothing easy. Trot out the heavy artillery... */
+
+ if (allow_opts & OPT_INDEXES) {
+ int errstatus;
+
+ if ((errstatus = ap_discard_request_body(r)) != OK) {
+ return errstatus;
+ }
+
+ /* KLUDGE --- make the sub_req lookups happen in the right directory.
+ * Fixing this in the sub_req_lookup functions themselves is difficult,
+ * and would probably break virtual includes...
+ */
+
+ if (r->filename[strlen(r->filename) - 1] != '/') {
+ r->filename = apr_pstrcat(r->pool, r->filename, "/", NULL);
+ }
+ return index_directory(r, d);
+ }
+ else {
+ const char *index_names = apr_table_get(r->notes, "dir-index-names");
+
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01276)
+ "Cannot serve directory %s: No matching DirectoryIndex (%s) found, and "
+ "server-generated directory index forbidden by "
+ "Options directive",
+ r->filename,
+ index_names ? index_names : "none");
+ return HTTP_FORBIDDEN;
+ }
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_hook_handler(handle_autoindex,NULL,NULL,APR_HOOK_MIDDLE);
+}
+
+AP_DECLARE_MODULE(autoindex) =
+{
+ STANDARD20_MODULE_STUFF,
+ create_autoindex_config, /* dir config creater */
+ merge_autoindex_configs, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ autoindex_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/generators/mod_autoindex.dep b/modules/generators/mod_autoindex.dep
new file mode 100644
index 0000000..1d5ca61
--- /dev/null
+++ b/modules/generators/mod_autoindex.dep
@@ -0,0 +1,61 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_autoindex.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_autoindex.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.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\mod_core.h"\
+ "..\..\include\os.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\include\util_script.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.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-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_fnmatch.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_hash.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_lib.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+
diff --git a/modules/generators/mod_autoindex.dsp b/modules/generators/mod_autoindex.dsp
new file mode 100644
index 0000000..1f6ec05
--- /dev/null
+++ b/modules/generators/mod_autoindex.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_autoindex" - 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_autoindex - 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_autoindex.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_autoindex.mak" CFG="mod_autoindex - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_autoindex - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_autoindex - 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_autoindex - 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_autoindex_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_autoindex.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_autoindex.so" /d LONG_NAME="autoindex_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_autoindex.so" /base:@..\..\os\win32\BaseAddr.ref,mod_autoindex.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_autoindex.so" /base:@..\..\os\win32\BaseAddr.ref,mod_autoindex.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_autoindex.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_autoindex - 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_autoindex_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_autoindex.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_autoindex.so" /d LONG_NAME="autoindex_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_autoindex.so" /base:@..\..\os\win32\BaseAddr.ref,mod_autoindex.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_autoindex.so" /base:@..\..\os\win32\BaseAddr.ref,mod_autoindex.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_autoindex.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_autoindex - Win32 Release"
+# Name "mod_autoindex - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_autoindex.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/generators/mod_autoindex.exp b/modules/generators/mod_autoindex.exp
new file mode 100644
index 0000000..90f4057
--- /dev/null
+++ b/modules/generators/mod_autoindex.exp
@@ -0,0 +1 @@
+autoindex_module
diff --git a/modules/generators/mod_autoindex.mak b/modules/generators/mod_autoindex.mak
new file mode 100644
index 0000000..daebb5d
--- /dev/null
+++ b/modules/generators/mod_autoindex.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_autoindex.dsp
+!IF "$(CFG)" == ""
+CFG=mod_autoindex - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_autoindex - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_autoindex - Win32 Release" && "$(CFG)" != "mod_autoindex - 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_autoindex.mak" CFG="mod_autoindex - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_autoindex - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_autoindex - 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_autoindex - 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_autoindex.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_autoindex.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_autoindex.obj"
+ -@erase "$(INTDIR)\mod_autoindex.res"
+ -@erase "$(INTDIR)\mod_autoindex_src.idb"
+ -@erase "$(INTDIR)\mod_autoindex_src.pdb"
+ -@erase "$(OUTDIR)\mod_autoindex.exp"
+ -@erase "$(OUTDIR)\mod_autoindex.lib"
+ -@erase "$(OUTDIR)\mod_autoindex.pdb"
+ -@erase "$(OUTDIR)\mod_autoindex.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_autoindex_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_autoindex.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_autoindex.so" /d LONG_NAME="autoindex_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_autoindex.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_autoindex.pdb" /debug /out:"$(OUTDIR)\mod_autoindex.so" /implib:"$(OUTDIR)\mod_autoindex.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_autoindex.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_autoindex.obj" \
+ "$(INTDIR)\mod_autoindex.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_autoindex.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_autoindex.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_autoindex.so"
+ if exist .\Release\mod_autoindex.so.manifest mt.exe -manifest .\Release\mod_autoindex.so.manifest -outputresource:.\Release\mod_autoindex.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_autoindex - 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_autoindex.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_autoindex.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_autoindex.obj"
+ -@erase "$(INTDIR)\mod_autoindex.res"
+ -@erase "$(INTDIR)\mod_autoindex_src.idb"
+ -@erase "$(INTDIR)\mod_autoindex_src.pdb"
+ -@erase "$(OUTDIR)\mod_autoindex.exp"
+ -@erase "$(OUTDIR)\mod_autoindex.lib"
+ -@erase "$(OUTDIR)\mod_autoindex.pdb"
+ -@erase "$(OUTDIR)\mod_autoindex.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_autoindex_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_autoindex.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_autoindex.so" /d LONG_NAME="autoindex_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_autoindex.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_autoindex.pdb" /debug /out:"$(OUTDIR)\mod_autoindex.so" /implib:"$(OUTDIR)\mod_autoindex.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_autoindex.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_autoindex.obj" \
+ "$(INTDIR)\mod_autoindex.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_autoindex.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_autoindex.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_autoindex.so"
+ if exist .\Debug\mod_autoindex.so.manifest mt.exe -manifest .\Debug\mod_autoindex.so.manifest -outputresource:.\Debug\mod_autoindex.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_autoindex.dep")
+!INCLUDE "mod_autoindex.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_autoindex.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_autoindex - Win32 Release" || "$(CFG)" == "mod_autoindex - Win32 Debug"
+
+!IF "$(CFG)" == "mod_autoindex - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_autoindex - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_autoindex - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_autoindex - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_autoindex - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_autoindex - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_autoindex - Win32 Release"
+
+
+"$(INTDIR)\mod_autoindex.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_autoindex.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_autoindex.so" /d LONG_NAME="autoindex_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_autoindex - Win32 Debug"
+
+
+"$(INTDIR)\mod_autoindex.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_autoindex.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_autoindex.so" /d LONG_NAME="autoindex_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_autoindex.c
+
+"$(INTDIR)\mod_autoindex.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c
new file mode 100644
index 0000000..8c4a2c6
--- /dev/null
+++ b/modules/generators/mod_cgi.c
@@ -0,0 +1,1281 @@
+/* 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.
+ */
+
+/*
+ * http_script: keeps all script-related ramblings together.
+ *
+ * Compliant to CGI/1.1 spec
+ *
+ * Adapted by rst from original NCSA code by Rob McCool
+ *
+ * This modules uses a httpd core function (ap_add_common_vars) to add some new env vars,
+ * like REDIRECT_URL and REDIRECT_QUERY_STRING for custom error responses and DOCUMENT_ROOT.
+ * It also adds SERVER_ADMIN - useful for scripts to know who to mail when they fail.
+ *
+ */
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_thread_proc.h" /* for RLIMIT stuff */
+#include "apr_optional.h"
+#include "apr_buckets.h"
+#include "apr_lib.h"
+#include "apr_poll.h"
+
+#define APR_WANT_STRFUNC
+#define APR_WANT_MEMFUNC
+#include "apr_want.h"
+
+#include "util_filter.h"
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "ap_mpm.h"
+#include "mod_core.h"
+#include "mod_cgi.h"
+
+#if APR_HAVE_STRUCT_RLIMIT
+#if defined (RLIMIT_CPU) || defined (RLIMIT_NPROC) || defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
+#define AP_CGI_USE_RLIMIT
+#endif
+#endif
+
+module AP_MODULE_DECLARE_DATA cgi_module;
+
+static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgi_pfn_reg_with_ssi;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgi_pfn_gtv;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgi_pfn_ps;
+static APR_OPTIONAL_FN_TYPE(ap_cgi_build_command) *cgi_build_command;
+
+/* Read and discard the data in the brigade produced by a CGI script */
+static void discard_script_output(apr_bucket_brigade *bb);
+
+/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
+ * in ScriptAliased directories, which means we need to know if this
+ * request came through ScriptAlias or not... so the Alias module
+ * leaves a note for us.
+ */
+
+static int is_scriptaliased(request_rec *r)
+{
+ const char *t = apr_table_get(r->notes, "alias-forced-type");
+ return t && (!strcasecmp(t, "cgi-script"));
+}
+
+/* Configuration stuff */
+
+#define DEFAULT_LOGBYTES 10385760
+#define DEFAULT_BUFBYTES 1024
+
+typedef struct {
+ const char *logname;
+ long logbytes;
+ apr_size_t bufbytes;
+} cgi_server_conf;
+
+static void *create_cgi_config(apr_pool_t *p, server_rec *s)
+{
+ cgi_server_conf *c =
+ (cgi_server_conf *) apr_pcalloc(p, sizeof(cgi_server_conf));
+
+ c->logname = NULL;
+ c->logbytes = DEFAULT_LOGBYTES;
+ c->bufbytes = DEFAULT_BUFBYTES;
+
+ return c;
+}
+
+static void *merge_cgi_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+ cgi_server_conf *base = (cgi_server_conf *) basev,
+ *overrides = (cgi_server_conf *) overridesv;
+
+ return overrides->logname ? overrides : base;
+}
+
+static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ server_rec *s = cmd->server;
+ cgi_server_conf *conf = ap_get_module_config(s->module_config,
+ &cgi_module);
+
+ conf->logname = ap_server_root_relative(cmd->pool, arg);
+
+ if (!conf->logname) {
+ return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",
+ arg, NULL);
+ }
+
+ return NULL;
+}
+
+static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ server_rec *s = cmd->server;
+ cgi_server_conf *conf = ap_get_module_config(s->module_config,
+ &cgi_module);
+
+ conf->logbytes = atol(arg);
+ return NULL;
+}
+
+static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ server_rec *s = cmd->server;
+ cgi_server_conf *conf = ap_get_module_config(s->module_config,
+ &cgi_module);
+
+ conf->bufbytes = atoi(arg);
+ return NULL;
+}
+
+static const command_rec cgi_cmds[] =
+{
+AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF,
+ "the name of a log for script debugging info"),
+AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,
+ "the maximum length (in bytes) of the script debug log"),
+AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,
+ "the maximum size (in bytes) to record of a POST request"),
+ {NULL}
+};
+
+static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret,
+ apr_status_t rv, char *logno, char *error)
+{
+ apr_file_t *f = NULL;
+ apr_finfo_t finfo;
+ char time_str[APR_CTIME_LEN];
+ int log_flags = rv ? APLOG_ERR : APLOG_ERR;
+
+ /* Intentional no APLOGNO */
+ /* Callee provides APLOGNO in error text */
+ ap_log_rerror(APLOG_MARK, log_flags, rv, r,
+ "%s%s: %s", logno ? logno : "", error, r->filename);
+
+ /* XXX Very expensive mainline case! Open, then getfileinfo! */
+ if (!conf->logname ||
+ ((apr_stat(&finfo, conf->logname,
+ APR_FINFO_SIZE, r->pool) == APR_SUCCESS) &&
+ (finfo.size > conf->logbytes)) ||
+ (apr_file_open(&f, conf->logname,
+ APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT,
+ r->pool) != APR_SUCCESS)) {
+ return ret;
+ }
+
+ /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
+ apr_ctime(time_str, apr_time_now());
+ apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
+ r->args ? "?" : "", r->args ? r->args : "", r->protocol);
+ /* "%% 500 /usr/local/apache/cgi-bin */
+ apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
+
+ apr_file_printf(f, "%%error\n%s\n", error);
+
+ apr_file_close(f);
+ return ret;
+}
+
+/* Soak up stderr from a script and redirect it to the error log.
+ */
+static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err)
+{
+ char argsbuffer[HUGE_STRING_LEN];
+ char *newline;
+ apr_status_t rv;
+ cgi_server_conf *conf = ap_get_module_config(r->server->module_config, &cgi_module);
+
+ while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN,
+ script_err)) == APR_SUCCESS) {
+ newline = strchr(argsbuffer, '\n');
+ if (newline) {
+ *newline = '\0';
+ }
+ log_scripterror(r, conf, r->status, 0, APLOGNO(01215), argsbuffer);
+ }
+
+ return rv;
+}
+
+static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
+ char *dbuf, const char *sbuf, apr_bucket_brigade *bb,
+ apr_file_t *script_err)
+{
+ const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);
+ const apr_table_entry_t *hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
+ char argsbuffer[HUGE_STRING_LEN];
+ apr_file_t *f = NULL;
+ apr_bucket *e;
+ const char *buf;
+ apr_size_t len;
+ apr_status_t rv;
+ int first;
+ int i;
+ apr_finfo_t finfo;
+ char time_str[APR_CTIME_LEN];
+
+ /* XXX Very expensive mainline case! Open, then getfileinfo! */
+ if (!conf->logname ||
+ ((apr_stat(&finfo, conf->logname,
+ APR_FINFO_SIZE, r->pool) == APR_SUCCESS) &&
+ (finfo.size > conf->logbytes)) ||
+ (apr_file_open(&f, conf->logname,
+ APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT,
+ r->pool) != APR_SUCCESS)) {
+ /* Soak up script output */
+ discard_script_output(bb);
+ log_script_err(r, script_err);
+ return ret;
+ }
+
+ /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
+ apr_ctime(time_str, apr_time_now());
+ apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
+ r->args ? "?" : "", r->args ? r->args : "", r->protocol);
+ /* "%% 500 /usr/local/apache/cgi-bin" */
+ apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
+
+ apr_file_puts("%request\n", f);
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (!hdrs[i].key)
+ continue;
+ apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
+ }
+ if ((r->method_number == M_POST || r->method_number == M_PUT) &&
+ *dbuf) {
+ apr_file_printf(f, "\n%s\n", dbuf);
+ }
+
+ apr_file_puts("%response\n", f);
+ hdrs_arr = apr_table_elts(r->err_headers_out);
+ hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
+
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (!hdrs[i].key)
+ continue;
+ apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
+ }
+
+ if (sbuf && *sbuf)
+ apr_file_printf(f, "%s\n", sbuf);
+
+ first = 1;
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ if (APR_BUCKET_IS_EOS(e)) {
+ break;
+ }
+ rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
+ if (rv != APR_SUCCESS || (len == 0)) {
+ break;
+ }
+ if (first) {
+ apr_file_puts("%stdout\n", f);
+ first = 0;
+ }
+ apr_file_write(f, buf, &len);
+ apr_file_puts("\n", f);
+ }
+
+ if (apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err) == APR_SUCCESS) {
+ apr_file_puts("%stderr\n", f);
+ apr_file_puts(argsbuffer, f);
+ while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
+ script_err) == APR_SUCCESS) {
+ apr_file_puts(argsbuffer, f);
+ }
+ apr_file_puts("\n", f);
+ }
+
+ apr_brigade_destroy(bb);
+ apr_file_close(script_err);
+
+ apr_file_close(f);
+ return ret;
+}
+
+
+/* This is the special environment used for running the "exec cmd="
+ * variety of SSI directives.
+ */
+static void add_ssi_vars(request_rec *r)
+{
+ apr_table_t *e = r->subprocess_env;
+
+ if (r->path_info && r->path_info[0] != '\0') {
+ request_rec *pa_req;
+
+ apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool,
+ r->path_info));
+
+ pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info),
+ r, NULL);
+ if (pa_req->filename) {
+ apr_table_setn(e, "PATH_TRANSLATED",
+ apr_pstrcat(r->pool, pa_req->filename,
+ pa_req->path_info, NULL));
+ }
+ ap_destroy_sub_req(pa_req);
+ }
+
+ if (r->args) {
+ char *arg_copy = apr_pstrdup(r->pool, r->args);
+
+ apr_table_setn(e, "QUERY_STRING", r->args);
+ ap_unescape_url(arg_copy);
+ apr_table_setn(e, "QUERY_STRING_UNESCAPED",
+ ap_escape_shell_cmd(r->pool, arg_copy));
+ }
+}
+
+static void cgi_child_errfn(apr_pool_t *pool, apr_status_t err,
+ const char *description)
+{
+ apr_file_t *stderr_log;
+
+ apr_file_open_stderr(&stderr_log, pool);
+ /* Escape the logged string because it may be something that
+ * came in over the network.
+ */
+ apr_file_printf(stderr_log,
+ "(%d)%pm: %s\n",
+ err,
+ &err,
+#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
+ ap_escape_logitem(pool,
+#endif
+ description
+#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
+ )
+#endif
+ );
+}
+
+static apr_status_t run_cgi_child(apr_file_t **script_out,
+ apr_file_t **script_in,
+ apr_file_t **script_err,
+ const char *command,
+ const char * const argv[],
+ request_rec *r,
+ apr_pool_t *p,
+ cgi_exec_info_t *e_info)
+{
+ const char * const *env;
+ apr_procattr_t *procattr;
+ apr_proc_t *procnew;
+ apr_status_t rc = APR_SUCCESS;
+
+#ifdef AP_CGI_USE_RLIMIT
+ core_dir_config *conf = ap_get_core_module_config(r->per_dir_config);
+#endif
+
+#ifdef DEBUG_CGI
+#ifdef OS2
+ /* Under OS/2 need to use device con. */
+ FILE *dbg = fopen("con", "w");
+#else
+ FILE *dbg = fopen("/dev/tty", "w");
+#endif
+ int i;
+#endif
+
+ RAISE_SIGSTOP(CGI_CHILD);
+#ifdef DEBUG_CGI
+ fprintf(dbg, "Attempting to exec %s as CGI child (argv0 = %s)\n",
+ r->filename, argv[0]);
+#endif
+
+ env = (const char * const *)ap_create_environment(p, r->subprocess_env);
+
+#ifdef DEBUG_CGI
+ fprintf(dbg, "Environment: \n");
+ for (i = 0; env[i]; ++i)
+ fprintf(dbg, "'%s'\n", env[i]);
+ fclose(dbg);
+#endif
+
+ /* Transmute ourselves into the script.
+ * NB only ISINDEX scripts get decoded arguments.
+ */
+ if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_io_set(procattr,
+ e_info->in_pipe,
+ e_info->out_pipe,
+ e_info->err_pipe)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_dir_set(procattr,
+ ap_make_dirstr_parent(r->pool,
+ r->filename))) != APR_SUCCESS) ||
+#if defined(RLIMIT_CPU) && defined(AP_CGI_USE_RLIMIT)
+ ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU,
+ conf->limit_cpu)) != APR_SUCCESS) ||
+#endif
+#if defined(AP_CGI_USE_RLIMIT) && (defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS))
+ ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM,
+ conf->limit_mem)) != APR_SUCCESS) ||
+#endif
+#if defined(RLIMIT_NPROC) && defined(AP_CGI_USE_RLIMIT)
+ ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC,
+ conf->limit_nproc)) != APR_SUCCESS) ||
+#endif
+ ((rc = apr_procattr_cmdtype_set(procattr,
+ e_info->cmd_type)) != APR_SUCCESS) ||
+
+ ((rc = apr_procattr_detach_set(procattr,
+ e_info->detached)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_addrspace_set(procattr,
+ e_info->addrspace)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) {
+ /* Something bad happened, tell the world. */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, APLOGNO(01216)
+ "couldn't set child process attributes: %s", r->filename);
+ }
+ else {
+ procnew = apr_pcalloc(p, sizeof(*procnew));
+ rc = ap_os_create_privileged_process(r, procnew, command, argv, env,
+ procattr, p);
+
+ if (rc != APR_SUCCESS) {
+ /* Bad things happened. Everyone should have cleaned up. */
+ /* Intentional no APLOGNO */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r,
+ "couldn't create child process: %d: %s", rc,
+ apr_filepath_name_get(r->filename));
+ }
+ else {
+ apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
+
+ *script_in = procnew->out;
+ if (!*script_in)
+ return APR_EBADF;
+ apr_file_pipe_timeout_set(*script_in, r->server->timeout);
+
+ if (e_info->prog_type == RUN_AS_CGI) {
+ *script_out = procnew->in;
+ if (!*script_out)
+ return APR_EBADF;
+ apr_file_pipe_timeout_set(*script_out, r->server->timeout);
+
+ *script_err = procnew->err;
+ if (!*script_err)
+ return APR_EBADF;
+ apr_file_pipe_timeout_set(*script_err, r->server->timeout);
+ }
+ }
+ }
+ return (rc);
+}
+
+
+static apr_status_t default_build_command(const char **cmd, const char ***argv,
+ request_rec *r, apr_pool_t *p,
+ cgi_exec_info_t *e_info)
+{
+ int numwords, x, idx;
+ char *w;
+ const char *args = NULL;
+
+ if (e_info->process_cgi) {
+ *cmd = r->filename;
+ /* Do not process r->args if they contain an '=' assignment
+ */
+ if (r->args && r->args[0] && !ap_strchr_c(r->args, '=')) {
+ args = r->args;
+ }
+ }
+
+ if (!args) {
+ numwords = 1;
+ }
+ else {
+ /* count the number of keywords */
+ for (x = 0, numwords = 2; args[x]; x++) {
+ if (args[x] == '+') {
+ ++numwords;
+ }
+ }
+ }
+ /* Everything is - 1 to account for the first parameter
+ * which is the program name.
+ */
+ if (numwords > APACHE_ARG_MAX - 1) {
+ numwords = APACHE_ARG_MAX - 1; /* Truncate args to prevent overrun */
+ }
+ *argv = apr_palloc(p, (numwords + 2) * sizeof(char *));
+ (*argv)[0] = *cmd;
+ for (x = 1, idx = 1; x < numwords; x++) {
+ w = ap_getword_nulls(p, &args, '+');
+ ap_unescape_url(w);
+ (*argv)[idx++] = ap_escape_shell_cmd(p, w);
+ }
+ (*argv)[idx] = NULL;
+
+ return APR_SUCCESS;
+}
+
+static void discard_script_output(apr_bucket_brigade *bb)
+{
+ apr_bucket *e;
+ const char *buf;
+ apr_size_t len;
+ apr_status_t rv;
+
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ if (APR_BUCKET_IS_EOS(e)) {
+ break;
+ }
+ rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
+ if (rv != APR_SUCCESS) {
+ break;
+ }
+ }
+}
+
+#if APR_FILES_AS_SOCKETS
+
+/* A CGI bucket type is needed to catch any output to stderr from the
+ * script; see PR 22030. */
+static const apr_bucket_type_t bucket_type_cgi;
+
+struct cgi_bucket_data {
+ apr_pollset_t *pollset;
+ request_rec *r;
+};
+
+/* Create a CGI bucket using pipes from script stdout 'out'
+ * and stderr 'err', for request 'r'. */
+static apr_bucket *cgi_bucket_create(request_rec *r,
+ apr_file_t *out, apr_file_t *err,
+ apr_bucket_alloc_t *list)
+{
+ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+ apr_status_t rv;
+ apr_pollfd_t fd;
+ struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data);
+
+ APR_BUCKET_INIT(b);
+ b->free = apr_bucket_free;
+ b->list = list;
+ b->type = &bucket_type_cgi;
+ b->length = (apr_size_t)(-1);
+ b->start = -1;
+
+ /* Create the pollset */
+ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217)
+ "apr_pollset_create(); check system or user limits");
+ return NULL;
+ }
+
+ fd.desc_type = APR_POLL_FILE;
+ fd.reqevents = APR_POLLIN;
+ fd.p = r->pool;
+ fd.desc.f = out; /* script's stdout */
+ fd.client_data = (void *)1;
+ rv = apr_pollset_add(data->pollset, &fd);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218)
+ "apr_pollset_add(); check system or user limits");
+ return NULL;
+ }
+
+ fd.desc.f = err; /* script's stderr */
+ fd.client_data = (void *)2;
+ rv = apr_pollset_add(data->pollset, &fd);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219)
+ "apr_pollset_add(); check system or user limits");
+ return NULL;
+ }
+
+ data->r = r;
+ b->data = data;
+ return b;
+}
+
+/* Create a duplicate CGI bucket using given bucket data */
+static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data,
+ 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->type = &bucket_type_cgi;
+ b->length = (apr_size_t)(-1);
+ b->start = -1;
+ b->data = data;
+ return b;
+}
+
+/* Handle stdout from CGI child. Duplicate of logic from the _read
+ * method of the real APR pipe bucket implementation. */
+static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out,
+ const char **str, apr_size_t *len)
+{
+ char *buf;
+ apr_status_t rv;
+
+ *str = NULL;
+ *len = APR_BUCKET_BUFF_SIZE;
+ buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */
+
+ rv = apr_file_read(out, buf, len);
+
+ if (rv != APR_SUCCESS && rv != APR_EOF) {
+ apr_bucket_free(buf);
+ return rv;
+ }
+
+ if (*len > 0) {
+ struct cgi_bucket_data *data = a->data;
+ apr_bucket_heap *h;
+
+ /* Change the current bucket to refer to what we read */
+ a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free);
+ h = a->data;
+ h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
+ *str = buf;
+ APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list));
+ }
+ else {
+ apr_bucket_free(buf);
+ a = apr_bucket_immortal_make(a, "", 0);
+ *str = a->data;
+ }
+ return rv;
+}
+
+/* Read method of CGI bucket: polls on stderr and stdout of the child,
+ * sending any stderr output immediately away to the error log. */
+static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str,
+ apr_size_t *len, apr_read_type_e block)
+{
+ struct cgi_bucket_data *data = b->data;
+ apr_interval_time_t timeout;
+ apr_status_t rv;
+ int gotdata = 0;
+
+ timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout;
+
+ do {
+ const apr_pollfd_t *results;
+ apr_int32_t num;
+
+ rv = apr_pollset_poll(data->pollset, timeout, &num, &results);
+ if (APR_STATUS_IS_TIMEUP(rv)) {
+ if (timeout) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220)
+ "Timeout waiting for output from CGI script %s",
+ data->r->filename);
+ return rv;
+ }
+ else {
+ return APR_EAGAIN;
+ }
+ }
+ else if (APR_STATUS_IS_EINTR(rv)) {
+ continue;
+ }
+ else if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221)
+ "poll failed waiting for CGI child");
+ return rv;
+ }
+
+ for (; num; num--, results++) {
+ if (results[0].client_data == (void *)1) {
+ /* stdout */
+ rv = cgi_read_stdout(b, results[0].desc.f, str, len);
+ if (APR_STATUS_IS_EOF(rv)) {
+ rv = APR_SUCCESS;
+ }
+ gotdata = 1;
+ } else {
+ /* stderr */
+ apr_status_t rv2 = log_script_err(data->r, results[0].desc.f);
+ if (APR_STATUS_IS_EOF(rv2)) {
+ apr_pollset_remove(data->pollset, &results[0]);
+ }
+ }
+ }
+
+ } while (!gotdata);
+
+ return rv;
+}
+
+static const apr_bucket_type_t bucket_type_cgi = {
+ "CGI", 5, APR_BUCKET_DATA,
+ apr_bucket_destroy_noop,
+ cgi_bucket_read,
+ apr_bucket_setaside_notimpl,
+ apr_bucket_split_notimpl,
+ apr_bucket_copy_notimpl
+};
+
+#endif
+
+static int cgi_handler(request_rec *r)
+{
+ int nph;
+ apr_size_t dbpos = 0;
+ const char *argv0;
+ const char *command;
+ const char **argv;
+ char *dbuf = NULL;
+ apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL;
+ apr_bucket_brigade *bb;
+ apr_bucket *b;
+ int is_included;
+ int seen_eos, child_stopped_reading;
+ apr_pool_t *p;
+ cgi_server_conf *conf;
+ apr_status_t rv;
+ cgi_exec_info_t e_info;
+ conn_rec *c;
+
+ if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) {
+ return DECLINED;
+ }
+
+ c = r->connection;
+
+ is_included = !strcmp(r->protocol, "INCLUDED");
+
+ p = r->main ? r->main->pool : r->pool;
+
+ argv0 = apr_filepath_name_get(r->filename);
+ nph = !(strncmp(argv0, "nph-", 4));
+ conf = ap_get_module_config(r->server->module_config, &cgi_module);
+
+ if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r))
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(02809),
+ "Options ExecCGI is off in this directory");
+ if (nph && is_included)
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(02810),
+ "attempt to include NPH CGI script");
+
+ if (r->finfo.filetype == APR_NOFILE)
+ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(02811),
+ "script not found or unable to stat");
+ if (r->finfo.filetype == APR_DIR)
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(02812),
+ "attempt to invoke directory as script");
+
+ if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) &&
+ r->path_info && *r->path_info)
+ {
+ /* default to accept */
+ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(02813),
+ "AcceptPathInfo off disallows user's path");
+ }
+/*
+ if (!ap_suexec_enabled) {
+ if (!ap_can_exec(&r->finfo))
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(03194)
+ "file permissions deny server execution");
+ }
+
+*/
+ ap_add_common_vars(r);
+ ap_add_cgi_vars(r);
+
+ e_info.process_cgi = 1;
+ e_info.cmd_type = APR_PROGRAM;
+ e_info.detached = 0;
+ e_info.in_pipe = APR_CHILD_BLOCK;
+ e_info.out_pipe = APR_CHILD_BLOCK;
+ e_info.err_pipe = APR_CHILD_BLOCK;
+ e_info.prog_type = RUN_AS_CGI;
+ e_info.bb = NULL;
+ e_info.ctx = NULL;
+ e_info.next = NULL;
+ e_info.addrspace = 0;
+
+ /* build the command line */
+ if ((rv = cgi_build_command(&command, &argv, r, p, &e_info)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01222)
+ "don't know how to spawn child process: %s",
+ r->filename);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* run the script in its own process */
+ if ((rv = run_cgi_child(&script_out, &script_in, &script_err,
+ command, argv, r, p, &e_info)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01223)
+ "couldn't spawn child process: %s", r->filename);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* Transfer any put/post args, CERN style...
+ * Note that we already ignore SIGPIPE in the core server.
+ */
+ bb = apr_brigade_create(r->pool, c->bucket_alloc);
+ seen_eos = 0;
+ child_stopped_reading = 0;
+ if (conf->logname) {
+ dbuf = apr_palloc(r->pool, conf->bufbytes + 1);
+ dbpos = 0;
+ }
+ do {
+ apr_bucket *bucket;
+
+ rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
+ APR_BLOCK_READ, HUGE_STRING_LEN);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01225)
+ "Error reading request entity data");
+ return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
+ }
+
+ for (bucket = APR_BRIGADE_FIRST(bb);
+ bucket != APR_BRIGADE_SENTINEL(bb);
+ bucket = APR_BUCKET_NEXT(bucket))
+ {
+ const char *data;
+ apr_size_t len;
+
+ if (APR_BUCKET_IS_EOS(bucket)) {
+ seen_eos = 1;
+ break;
+ }
+
+ /* We can't do much with this. */
+ if (APR_BUCKET_IS_FLUSH(bucket)) {
+ continue;
+ }
+
+ /* If the child stopped, we still must read to EOS. */
+ if (child_stopped_reading) {
+ continue;
+ }
+
+ /* read */
+ apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
+
+ if (conf->logname && dbpos < conf->bufbytes) {
+ int cursize;
+
+ if ((dbpos + len) > conf->bufbytes) {
+ cursize = conf->bufbytes - dbpos;
+ }
+ else {
+ cursize = len;
+ }
+ memcpy(dbuf + dbpos, data, cursize);
+ dbpos += cursize;
+ }
+
+ /* Keep writing data to the child until done or too much time
+ * elapses with no progress or an error occurs.
+ */
+ rv = apr_file_write_full(script_out, data, len, NULL);
+
+ if (rv != APR_SUCCESS) {
+ /* silly script stopped reading, soak up remaining message */
+ child_stopped_reading = 1;
+ }
+ }
+ apr_brigade_cleanup(bb);
+ }
+ while (!seen_eos);
+
+ if (conf->logname) {
+ dbuf[dbpos] = '\0';
+ }
+ /* Is this flush really needed? */
+ apr_file_flush(script_out);
+ apr_file_close(script_out);
+
+ AP_DEBUG_ASSERT(script_in != NULL);
+
+#if APR_FILES_AS_SOCKETS
+ apr_file_pipe_timeout_set(script_in, 0);
+ apr_file_pipe_timeout_set(script_err, 0);
+
+ b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc);
+ if (b == NULL)
+ return HTTP_INTERNAL_SERVER_ERROR;
+#else
+ b = apr_bucket_pipe_create(script_in, c->bucket_alloc);
+#endif
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ b = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+
+ /* Handle script return... */
+ if (!nph) {
+ const char *location;
+ char sbuf[MAX_STRING_LEN];
+ int ret;
+
+ if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
+ APLOG_MODULE_INDEX)))
+ {
+ ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err);
+
+ /*
+ * ret could be HTTP_NOT_MODIFIED in the case that the CGI script
+ * does not set an explicit status and ap_meets_conditions, which
+ * is called by ap_scan_script_header_err_brigade, detects that
+ * the conditions of the requests are met and the response is
+ * not modified.
+ * In this case set r->status and return OK in order to prevent
+ * running through the error processing stack as this would
+ * break with mod_cache, if the conditions had been set by
+ * mod_cache itself to validate a stale entity.
+ * BTW: We circumvent the error processing stack anyway if the
+ * CGI script set an explicit status code (whatever it is) and
+ * the only possible values for ret here are:
+ *
+ * HTTP_NOT_MODIFIED (set by ap_meets_conditions)
+ * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions)
+ * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the
+ * processing of the response of the CGI script, e.g broken headers
+ * or a crashed CGI process).
+ */
+ if (ret == HTTP_NOT_MODIFIED) {
+ r->status = ret;
+ return OK;
+ }
+
+ return ret;
+ }
+
+ location = apr_table_get(r->headers_out, "Location");
+
+ if (location && r->status == 200) {
+ /* For a redirect whether internal or not, discard any
+ * remaining stdout from the script, and log any remaining
+ * stderr output, as normal. */
+ discard_script_output(bb);
+ apr_brigade_destroy(bb);
+ apr_file_pipe_timeout_set(script_err, r->server->timeout);
+ log_script_err(r, script_err);
+ }
+
+ if (location && location[0] == '/' && r->status == 200) {
+ /* This redirect needs to be a GET no matter what the original
+ * method was.
+ */
+ r->method = "GET";
+ r->method_number = M_GET;
+
+ /* We already read the message body (if any), so don't allow
+ * the redirected request to think it has one. We can ignore
+ * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
+ */
+ apr_table_unset(r->headers_in, "Content-Length");
+
+ ap_internal_redirect_handler(location, r);
+ return OK;
+ }
+ else if (location && r->status == 200) {
+ /* XXX: Note that if a script wants to produce its own Redirect
+ * body, it now has to explicitly *say* "Status: 302"
+ */
+ return HTTP_MOVED_TEMPORARILY;
+ }
+
+ rv = ap_pass_brigade(r->output_filters, bb);
+ }
+ else /* nph */ {
+ struct ap_filter_t *cur;
+
+ /* get rid of all filters up through protocol... since we
+ * haven't parsed off the headers, there is no way they can
+ * work
+ */
+
+ cur = r->proto_output_filters;
+ while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
+ cur = cur->next;
+ }
+ r->output_filters = r->proto_output_filters = cur;
+
+ rv = ap_pass_brigade(r->output_filters, bb);
+ }
+
+ /* don't soak up script output if errors occurred writing it
+ * out... otherwise, we prolong the life of the script when the
+ * connection drops or we stopped sending output for some other
+ * reason */
+ if (rv == APR_SUCCESS && !r->connection->aborted) {
+ apr_file_pipe_timeout_set(script_err, r->server->timeout);
+ log_script_err(r, script_err);
+ }
+
+ apr_file_close(script_err);
+
+ return OK; /* NOT r->status, even if it has changed. */
+}
+
+/*============================================================================
+ *============================================================================
+ * This is the beginning of the cgi filter code moved from mod_include. This
+ * is the code required to handle the "exec" SSI directive.
+ *============================================================================
+ *============================================================================*/
+static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *bb, char *s)
+{
+ request_rec *r = f->r;
+ request_rec *rr = ap_sub_req_lookup_uri(s, r, f->next);
+ int rr_status;
+
+ if (rr->status != HTTP_OK) {
+ ap_destroy_sub_req(rr);
+ return APR_EGENERAL;
+ }
+
+ /* No hardwired path info or query allowed */
+ if ((rr->path_info && rr->path_info[0]) || rr->args) {
+ ap_destroy_sub_req(rr);
+ return APR_EGENERAL;
+ }
+ if (rr->finfo.filetype != APR_REG) {
+ ap_destroy_sub_req(rr);
+ return APR_EGENERAL;
+ }
+
+ /* Script gets parameters of the *document*, for back compatibility */
+ rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */
+ rr->args = r->args;
+
+ /* Force sub_req to be treated as a CGI request, even if ordinary
+ * typing rules would have called it something else.
+ */
+ ap_set_content_type(rr, CGI_MAGIC_TYPE);
+
+ /* Run it. */
+ rr_status = ap_run_sub_req(rr);
+ if (ap_is_HTTP_REDIRECT(rr_status)) {
+ const char *location = apr_table_get(rr->headers_out, "Location");
+
+ if (location) {
+ char *buffer;
+
+ location = ap_escape_html(rr->pool, location);
+ buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">",
+ location, "</a>", NULL);
+
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buffer,
+ strlen(buffer), ctx->pool,
+ f->c->bucket_alloc));
+ }
+ }
+
+ ap_destroy_sub_req(rr);
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t include_cmd(include_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *bb, const char *command)
+{
+ cgi_exec_info_t e_info;
+ const char **argv;
+ apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL;
+ apr_status_t rv;
+ request_rec *r = f->r;
+
+ add_ssi_vars(r);
+
+ e_info.process_cgi = 0;
+ e_info.cmd_type = APR_SHELLCMD;
+ e_info.detached = 0;
+ e_info.in_pipe = APR_NO_PIPE;
+ e_info.out_pipe = APR_FULL_BLOCK;
+ e_info.err_pipe = APR_NO_PIPE;
+ e_info.prog_type = RUN_AS_SSI;
+ e_info.bb = &bb;
+ e_info.ctx = ctx;
+ e_info.next = f->next;
+ e_info.addrspace = 0;
+
+ if ((rv = cgi_build_command(&command, &argv, r, r->pool,
+ &e_info)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01226)
+ "don't know how to spawn cmd child process: %s",
+ r->filename);
+ return rv;
+ }
+
+ /* run the script in its own process */
+ if ((rv = run_cgi_child(&script_out, &script_in, &script_err,
+ command, argv, r, r->pool,
+ &e_info)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01227)
+ "couldn't spawn child process: %s", r->filename);
+ return rv;
+ }
+
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pipe_create(script_in,
+ f->c->bucket_alloc));
+ ctx->flush_now = 1;
+
+ /* We can't close the pipe here, because we may return before the
+ * full CGI has been sent to the network. That's okay though,
+ * because we can rely on the pool to close the pipe for us.
+ */
+ return APR_SUCCESS;
+}
+
+static apr_status_t handle_exec(include_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *bb)
+{
+ char *tag = NULL;
+ char *tag_val = NULL;
+ request_rec *r = f->r;
+ char *file = r->filename;
+ char parsed_string[MAX_STRING_LEN];
+
+ if (!ctx->argc) {
+ ap_log_rerror(APLOG_MARK,
+ (ctx->flags & SSI_FLAG_PRINTING)
+ ? APLOG_ERR : APLOG_WARNING,
+ 0, r, APLOGNO(03195)
+ "missing argument for exec element in %s", r->filename);
+ }
+
+ if (!(ctx->flags & SSI_FLAG_PRINTING)) {
+ return APR_SUCCESS;
+ }
+
+ if (!ctx->argc) {
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ return APR_SUCCESS;
+ }
+
+ if (ctx->flags & SSI_FLAG_NO_EXEC) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01228) "exec used but not allowed "
+ "in %s", r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ return APR_SUCCESS;
+ }
+
+ while (1) {
+ cgi_pfn_gtv(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
+ if (!tag || !tag_val) {
+ break;
+ }
+
+ if (!strcmp(tag, "cmd")) {
+ apr_status_t rv;
+
+ cgi_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string),
+ SSI_EXPAND_LEAVE_NAME);
+
+ rv = include_cmd(ctx, f, bb, parsed_string);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01229) "execution failure "
+ "for parameter \"%s\" to tag exec in file %s",
+ tag, r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ break;
+ }
+ }
+ else if (!strcmp(tag, "cgi")) {
+ apr_status_t rv;
+
+ cgi_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string),
+ SSI_EXPAND_DROP_NAME);
+
+ rv = include_cgi(ctx, f, bb, parsed_string);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01230) "invalid CGI ref "
+ "\"%s\" in %s", tag_val, file);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ break;
+ }
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01231) "unknown parameter "
+ "\"%s\" to tag exec in %s", tag, file);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ break;
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
+
+/*============================================================================
+ *============================================================================
+ * This is the end of the cgi filter code moved from mod_include.
+ *============================================================================
+ *============================================================================*/
+
+
+static int cgi_post_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ cgi_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
+ cgi_pfn_gtv = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
+ cgi_pfn_ps = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
+
+ if ((cgi_pfn_reg_with_ssi) && (cgi_pfn_gtv) && (cgi_pfn_ps)) {
+ /* Required by mod_include filter. This is how mod_cgi registers
+ * with mod_include to provide processing of the exec directive.
+ */
+ cgi_pfn_reg_with_ssi("exec", handle_exec);
+ }
+
+ /* This is the means by which unusual (non-unix) os's may find alternate
+ * means to run a given command (e.g. shebang/registry parsing on Win32)
+ */
+ cgi_build_command = APR_RETRIEVE_OPTIONAL_FN(ap_cgi_build_command);
+ if (!cgi_build_command) {
+ cgi_build_command = default_build_command;
+ }
+ return OK;
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+ static const char * const aszPre[] = { "mod_include.c", NULL };
+ ap_hook_handler(cgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_post_config(cgi_post_config, aszPre, NULL, APR_HOOK_REALLY_FIRST);
+}
+
+AP_DECLARE_MODULE(cgi) =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ create_cgi_config, /* server config */
+ merge_cgi_config, /* merge server config */
+ cgi_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/generators/mod_cgi.dep b/modules/generators/mod_cgi.dep
new file mode 100644
index 0000000..3da4698
--- /dev/null
+++ b/modules/generators/mod_cgi.dep
@@ -0,0 +1,64 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_cgi.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_cgi.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_mpm.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.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\mod_core.h"\
+ "..\..\include\mod_include.h"\
+ "..\..\include\os.h"\
+ "..\..\include\scoreboard.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\include\util_script.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.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-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_hash.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_lib.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+ ".\mod_cgi.h"\
+
diff --git a/modules/generators/mod_cgi.dsp b/modules/generators/mod_cgi.dsp
new file mode 100644
index 0000000..4fe58e0
--- /dev/null
+++ b/modules/generators/mod_cgi.dsp
@@ -0,0 +1,115 @@
+# Microsoft Developer Studio Project File - Name="mod_cgi" - 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_cgi - 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_cgi.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_cgi.mak" CFG="mod_cgi - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_cgi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_cgi - 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_cgi - 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_cgi_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_cgi.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_cgi.so" /d LONG_NAME="cgi_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_cgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_cgi.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_cgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_cgi.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_cgi.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_cgi - 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_cgi_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_cgi.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_cgi.so" /d LONG_NAME="cgi_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_cgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_cgi.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_cgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_cgi.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_cgi.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_cgi - Win32 Release"
+# Name "mod_cgi - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_cgi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_cgi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/generators/mod_cgi.exp b/modules/generators/mod_cgi.exp
new file mode 100644
index 0000000..96ea0c2
--- /dev/null
+++ b/modules/generators/mod_cgi.exp
@@ -0,0 +1 @@
+cgi_module
diff --git a/modules/generators/mod_cgi.h b/modules/generators/mod_cgi.h
new file mode 100644
index 0000000..424c6f2
--- /dev/null
+++ b/modules/generators/mod_cgi.h
@@ -0,0 +1,67 @@
+/* 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.
+ */
+
+/**
+ * @file mod_cgi.h
+ * @brief CGI Script Execution Extension Module for Apache
+ *
+ * @defgroup MOD_CGI mod_cgi
+ * @ingroup APACHE_MODS
+ * @{
+ */
+
+#ifndef _MOD_CGI_H
+#define _MOD_CGI_H 1
+
+#include "mod_include.h"
+
+typedef enum {RUN_AS_SSI, RUN_AS_CGI} prog_types;
+
+typedef struct {
+ apr_int32_t in_pipe;
+ apr_int32_t out_pipe;
+ apr_int32_t err_pipe;
+ int process_cgi;
+ apr_cmdtype_e cmd_type;
+ apr_int32_t detached;
+ prog_types prog_type;
+ apr_bucket_brigade **bb;
+ include_ctx_t *ctx;
+ ap_filter_t *next;
+ apr_int32_t addrspace;
+} cgi_exec_info_t;
+
+/**
+ * Registerable optional function to override CGI behavior;
+ * Reprocess the command and arguments to execute the given CGI script.
+ * @param cmd Pointer to the command to execute (may be overridden)
+ * @param argv Pointer to the arguments to pass (may be overridden)
+ * @param r The current request
+ * @param p The pool to allocate correct cmd/argv elements within.
+ * @param e_info pass e_info.cmd_type (Set to APR_SHELLCMD or APR_PROGRAM on entry)
+ and e_info.detached (Should the child start in detached state?)
+ * @remark This callback may be registered by the os-specific module
+ * to correct the command and arguments for apr_proc_create invocation
+ * on a given os. mod_cgi will call the function if registered.
+ */
+APR_DECLARE_OPTIONAL_FN(apr_status_t, ap_cgi_build_command,
+ (const char **cmd, const char ***argv,
+ request_rec *r, apr_pool_t *p,
+ cgi_exec_info_t *e_info));
+
+#endif /* _MOD_CGI_H */
+/** @} */
+
diff --git a/modules/generators/mod_cgi.mak b/modules/generators/mod_cgi.mak
new file mode 100644
index 0000000..bd5e7e7
--- /dev/null
+++ b/modules/generators/mod_cgi.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_cgi.dsp
+!IF "$(CFG)" == ""
+CFG=mod_cgi - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_cgi - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_cgi - Win32 Release" && "$(CFG)" != "mod_cgi - 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_cgi.mak" CFG="mod_cgi - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_cgi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_cgi - 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_cgi - 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_cgi.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_cgi.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_cgi.obj"
+ -@erase "$(INTDIR)\mod_cgi.res"
+ -@erase "$(INTDIR)\mod_cgi_src.idb"
+ -@erase "$(INTDIR)\mod_cgi_src.pdb"
+ -@erase "$(OUTDIR)\mod_cgi.exp"
+ -@erase "$(OUTDIR)\mod_cgi.lib"
+ -@erase "$(OUTDIR)\mod_cgi.pdb"
+ -@erase "$(OUTDIR)\mod_cgi.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_cgi_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_cgi.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_cgi.so" /d LONG_NAME="cgi_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_cgi.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_cgi.pdb" /debug /out:"$(OUTDIR)\mod_cgi.so" /implib:"$(OUTDIR)\mod_cgi.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_cgi.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_cgi.obj" \
+ "$(INTDIR)\mod_cgi.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_cgi.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_cgi.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_cgi.so"
+ if exist .\Release\mod_cgi.so.manifest mt.exe -manifest .\Release\mod_cgi.so.manifest -outputresource:.\Release\mod_cgi.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_cgi - 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_cgi.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_cgi.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_cgi.obj"
+ -@erase "$(INTDIR)\mod_cgi.res"
+ -@erase "$(INTDIR)\mod_cgi_src.idb"
+ -@erase "$(INTDIR)\mod_cgi_src.pdb"
+ -@erase "$(OUTDIR)\mod_cgi.exp"
+ -@erase "$(OUTDIR)\mod_cgi.lib"
+ -@erase "$(OUTDIR)\mod_cgi.pdb"
+ -@erase "$(OUTDIR)\mod_cgi.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_cgi_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_cgi.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_cgi.so" /d LONG_NAME="cgi_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_cgi.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_cgi.pdb" /debug /out:"$(OUTDIR)\mod_cgi.so" /implib:"$(OUTDIR)\mod_cgi.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_cgi.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_cgi.obj" \
+ "$(INTDIR)\mod_cgi.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_cgi.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_cgi.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_cgi.so"
+ if exist .\Debug\mod_cgi.so.manifest mt.exe -manifest .\Debug\mod_cgi.so.manifest -outputresource:.\Debug\mod_cgi.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_cgi.dep")
+!INCLUDE "mod_cgi.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_cgi.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_cgi - Win32 Release" || "$(CFG)" == "mod_cgi - Win32 Debug"
+
+!IF "$(CFG)" == "mod_cgi - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_cgi - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_cgi - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_cgi - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_cgi - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_cgi - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_cgi - Win32 Release"
+
+
+"$(INTDIR)\mod_cgi.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_cgi.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_cgi.so" /d LONG_NAME="cgi_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_cgi - Win32 Debug"
+
+
+"$(INTDIR)\mod_cgi.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_cgi.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_cgi.so" /d LONG_NAME="cgi_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_cgi.c
+
+"$(INTDIR)\mod_cgi.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c
new file mode 100644
index 0000000..b827ed6
--- /dev/null
+++ b/modules/generators/mod_cgid.c
@@ -0,0 +1,1980 @@
+/* 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.
+ */
+
+/*
+ * http_script: keeps all script-related ramblings together.
+ *
+ * Compliant to cgi/1.1 spec
+ *
+ * Adapted by rst from original NCSA code by Rob McCool
+ *
+ * This modules uses a httpd core function (ap_add_common_vars) to add some new env vars,
+ * like REDIRECT_URL and REDIRECT_QUERY_STRING for custom error responses and DOCUMENT_ROOT.
+ * It also adds SERVER_ADMIN - useful for scripts to know who to mail when they fail.
+ *
+ */
+
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_general.h"
+#include "apr_file_io.h"
+#include "apr_portable.h"
+#include "apr_buckets.h"
+#include "apr_optional.h"
+#include "apr_signal.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#if APR_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "util_filter.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "ap_mpm.h"
+#include "mpm_common.h"
+#include "mod_suexec.h"
+#include "../filters/mod_include.h"
+
+#include "mod_core.h"
+
+
+/* ### should be tossed in favor of APR */
+#include <sys/stat.h>
+#include <sys/un.h> /* for sockaddr_un */
+
+#if APR_HAVE_STRUCT_RLIMIT
+#if defined (RLIMIT_CPU) || defined (RLIMIT_NPROC) || defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
+#define AP_CGID_USE_RLIMIT
+#endif
+#endif
+
+module AP_MODULE_DECLARE_DATA cgid_module;
+
+static int cgid_start(apr_pool_t *p, server_rec *main_server, apr_proc_t *procnew);
+static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server);
+static int handle_exec(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb);
+
+static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgid_pfn_reg_with_ssi;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgid_pfn_gtv;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgid_pfn_ps;
+
+static apr_pool_t *pcgi = NULL;
+static pid_t daemon_pid;
+static int daemon_should_exit = 0;
+static server_rec *root_server = NULL;
+static apr_pool_t *root_pool = NULL;
+static const char *sockname;
+static struct sockaddr_un *server_addr;
+static apr_socklen_t server_addr_len;
+static pid_t parent_pid;
+static ap_unix_identity_t empty_ugid = { (uid_t)-1, (gid_t)-1, -1 };
+
+typedef struct {
+ apr_interval_time_t timeout;
+} cgid_dirconf;
+
+/* The APR other-child API doesn't tell us how the daemon exited
+ * (SIGSEGV vs. exit(1)). The other-child maintenance function
+ * needs to decide whether to restart the daemon after a failure
+ * based on whether or not it exited due to a fatal startup error
+ * or something that happened at steady-state. This exit status
+ * is unlikely to collide with exit signals.
+ */
+#define DAEMON_STARTUP_ERROR 254
+
+/* Read and discard the data in the brigade produced by a CGI script */
+static void discard_script_output(apr_bucket_brigade *bb);
+
+/* This doer will only ever be called when we are sure that we have
+ * a valid ugid.
+ */
+static ap_unix_identity_t *cgid_suexec_id_doer(const request_rec *r)
+{
+ return (ap_unix_identity_t *)
+ ap_get_module_config(r->request_config, &cgid_module);
+}
+
+/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
+ * in ScriptAliased directories, which means we need to know if this
+ * request came through ScriptAlias or not... so the Alias module
+ * leaves a note for us.
+ */
+
+static int is_scriptaliased(request_rec *r)
+{
+ const char *t = apr_table_get(r->notes, "alias-forced-type");
+ return t && (!strcasecmp(t, "cgi-script"));
+}
+
+/* Configuration stuff */
+
+#define DEFAULT_LOGBYTES 10385760
+#define DEFAULT_BUFBYTES 1024
+#define DEFAULT_SOCKET "cgisock"
+
+#define CGI_REQ 1
+#define SSI_REQ 2
+#define GETPID_REQ 3 /* get the pid of script created for prior request */
+
+#define ERRFN_USERDATA_KEY "CGIDCHILDERRFN"
+
+/* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's
+ * pending connection queue. If a bunch of cgi requests arrive at about
+ * the same time, connections from httpd threads/processes will back up
+ * in the queue while the cgid process slowly forks off a child to process
+ * each connection on the unix socket. If the queue is too short, the
+ * httpd process will get ECONNREFUSED when trying to connect.
+ */
+#ifndef DEFAULT_CGID_LISTENBACKLOG
+#define DEFAULT_CGID_LISTENBACKLOG 100
+#endif
+
+/* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect
+ * to the cgi daemon from the thread/process handling the cgi request.
+ * Generally we want to retry when we get ECONNREFUSED since it is
+ * probably because the listen queue is full. We need to try harder so
+ * the client doesn't see it as a 503 error.
+ *
+ * Set this to 0 to continually retry until the connect works or Apache
+ * terminates.
+ */
+#ifndef DEFAULT_CONNECT_ATTEMPTS
+#define DEFAULT_CONNECT_ATTEMPTS 15
+#endif
+
+#ifndef DEFAULT_CONNECT_STARTUP_DELAY
+#define DEFAULT_CONNECT_STARTUP_DELAY 60
+#endif
+
+typedef struct {
+ const char *logname;
+ long logbytes;
+ int bufbytes;
+} cgid_server_conf;
+
+#ifdef AP_CGID_USE_RLIMIT
+typedef struct {
+#ifdef RLIMIT_CPU
+ int limit_cpu_set;
+ struct rlimit limit_cpu;
+#endif
+#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
+ int limit_mem_set;
+ struct rlimit limit_mem;
+#endif
+#ifdef RLIMIT_NPROC
+ int limit_nproc_set;
+ struct rlimit limit_nproc;
+#endif
+
+} cgid_rlimit_t;
+#endif
+
+typedef struct {
+ int req_type; /* request type (CGI_REQ, SSI_REQ, etc.) */
+ unsigned long conn_id; /* connection id; daemon uses this as a hash value
+ * to find the script pid when it is time for that
+ * process to be cleaned up
+ */
+ pid_t ppid; /* sanity check for config problems leading to
+ * wrong cgid socket use
+ */
+ int env_count;
+ ap_unix_identity_t ugid;
+ apr_size_t filename_len;
+ apr_size_t argv0_len;
+ apr_size_t uri_len;
+ apr_size_t args_len;
+ int loglevel; /* to stuff in server_rec */
+
+#ifdef AP_CGID_USE_RLIMIT
+ cgid_rlimit_t limits;
+#endif
+} cgid_req_t;
+
+/* This routine is called to create the argument list to be passed
+ * to the CGI script. When suexec is enabled, the suexec path, user, and
+ * group are the first three arguments to be passed; if not, all three
+ * must be NULL. The query info is split into separate arguments, where
+ * "+" is the separator between keyword arguments.
+ *
+ * Do not process the args if they containing an '=' assignment.
+ */
+static char **create_argv(apr_pool_t *p, char *path, char *user, char *group,
+ char *av0, const char *args)
+{
+ int x, numwords;
+ char **av;
+ char *w;
+ int idx = 0;
+
+ if (!(*args) || ap_strchr_c(args, '=')) {
+ numwords = 0;
+ }
+ else {
+ /* count the number of keywords */
+
+ for (x = 0, numwords = 1; args[x]; x++) {
+ if (args[x] == '+') {
+ ++numwords;
+ }
+ }
+ }
+
+ if (numwords > APACHE_ARG_MAX - 5) {
+ numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */
+ }
+ av = (char **) apr_pcalloc(p, (numwords + 5) * sizeof(char *));
+
+ if (path) {
+ av[idx++] = path;
+ }
+ if (user) {
+ av[idx++] = user;
+ }
+ if (group) {
+ av[idx++] = group;
+ }
+
+ av[idx++] = apr_pstrdup(p, av0);
+
+ for (x = 1; x <= numwords; x++) {
+ w = ap_getword_nulls(p, &args, '+');
+ ap_unescape_url(w);
+ av[idx++] = ap_escape_shell_cmd(p, w);
+ }
+ av[idx] = NULL;
+ return av;
+}
+
+#if APR_HAS_OTHER_CHILD
+static void cgid_maint(int reason, void *data, apr_wait_t status)
+{
+ apr_proc_t *proc = data;
+ int mpm_state;
+ int stopping;
+
+ switch (reason) {
+ case APR_OC_REASON_DEATH:
+ apr_proc_other_child_unregister(data);
+ /* If apache is not terminating or restarting,
+ * restart the cgid daemon
+ */
+ stopping = 1; /* if MPM doesn't support query,
+ * assume we shouldn't restart daemon
+ */
+ if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state) == APR_SUCCESS &&
+ mpm_state != AP_MPMQ_STOPPING) {
+ stopping = 0;
+ }
+ if (!stopping) {
+ if (status == DAEMON_STARTUP_ERROR) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, APLOGNO(01238)
+ "cgid daemon failed to initialize");
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(01239)
+ "cgid daemon process died, restarting");
+ cgid_start(root_pool, root_server, proc);
+ }
+ }
+ break;
+ case APR_OC_REASON_RESTART:
+ /* don't do anything; server is stopping or restarting */
+ apr_proc_other_child_unregister(data);
+ break;
+ case APR_OC_REASON_LOST:
+ /* Restart the child cgid daemon process */
+ apr_proc_other_child_unregister(data);
+ cgid_start(root_pool, root_server, proc);
+ break;
+ case APR_OC_REASON_UNREGISTER:
+ /* we get here when pcgi is cleaned up; pcgi gets cleaned
+ * up when pconf gets cleaned up
+ */
+ kill(proc->pid, SIGHUP); /* send signal to daemon telling it to die */
+
+ /* Remove the cgi socket, we must do it here in order to try and
+ * guarantee the same permissions as when the socket was created.
+ */
+ if (unlink(sockname) < 0 && errno != ENOENT) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, APLOGNO(01240)
+ "Couldn't unlink unix domain socket %s",
+ sockname);
+ }
+ break;
+ }
+}
+#endif
+
+static apr_status_t close_unix_socket(void *thefd)
+{
+ int fd = (int)((long)thefd);
+
+ return close(fd);
+}
+
+/* deal with incomplete reads and signals
+ * assume you really have to read buf_size bytes
+ */
+static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size)
+{
+ char *buf = vbuf;
+ int rc;
+ size_t bytes_read = 0;
+
+ do {
+ do {
+ rc = read(fd, buf + bytes_read, buf_size - bytes_read);
+ } while (rc < 0 && errno == EINTR);
+ switch(rc) {
+ case -1:
+ return errno;
+ case 0: /* unexpected */
+ return ECONNRESET;
+ default:
+ bytes_read += rc;
+ }
+ } while (bytes_read < buf_size);
+
+ return APR_SUCCESS;
+}
+
+/* deal with signals
+ */
+static apr_status_t sock_write(int fd, const void *buf, size_t buf_size)
+{
+ int rc;
+
+ do {
+ rc = write(fd, buf, buf_size);
+ } while (rc < 0 && errno == EINTR);
+ if (rc < 0) {
+ return errno;
+ }
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t sock_writev(int fd, request_rec *r, int count, ...)
+{
+ va_list ap;
+ int rc;
+ struct iovec *vec;
+ int i;
+
+ vec = (struct iovec *)apr_palloc(r->pool, count * sizeof(struct iovec));
+ va_start(ap, count);
+ for (i = 0; i < count; i++) {
+ vec[i].iov_base = va_arg(ap, caddr_t);
+ vec[i].iov_len = va_arg(ap, apr_size_t);
+ }
+ va_end(ap);
+
+ do {
+ rc = writev(fd, vec, count);
+ } while (rc < 0 && errno == EINTR);
+ if (rc < 0) {
+ return errno;
+ }
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env,
+ cgid_req_t *req)
+{
+ int i;
+ char **environ;
+ core_request_config *temp_core;
+ void **rconf;
+ apr_status_t stat;
+
+ r->server = apr_pcalloc(r->pool, sizeof(server_rec));
+
+ /* read the request header */
+ stat = sock_read(fd, req, sizeof(*req));
+ if (stat != APR_SUCCESS) {
+ return stat;
+ }
+ r->server->log.level = req->loglevel;
+ if (req->req_type == GETPID_REQ) {
+ /* no more data sent for this request */
+ return APR_SUCCESS;
+ }
+
+ /* handle module indexes and such */
+ rconf = (void **)ap_create_request_config(r->pool);
+
+ temp_core = (core_request_config *)apr_palloc(r->pool, sizeof(core_module));
+ rconf[AP_CORE_MODULE_INDEX] = (void *)temp_core;
+ r->request_config = (ap_conf_vector_t *)rconf;
+ ap_set_module_config(r->request_config, &cgid_module, (void *)&req->ugid);
+
+ /* Read the filename, argv0, uri, and args */
+ r->filename = apr_pcalloc(r->pool, req->filename_len + 1);
+ *argv0 = apr_pcalloc(r->pool, req->argv0_len + 1);
+ r->uri = apr_pcalloc(r->pool, req->uri_len + 1);
+ if ((stat = sock_read(fd, r->filename, req->filename_len)) != APR_SUCCESS ||
+ (stat = sock_read(fd, *argv0, req->argv0_len)) != APR_SUCCESS ||
+ (stat = sock_read(fd, r->uri, req->uri_len)) != APR_SUCCESS) {
+ return stat;
+ }
+
+ r->args = apr_pcalloc(r->pool, req->args_len + 1); /* empty string if no args */
+ if (req->args_len) {
+ if ((stat = sock_read(fd, r->args, req->args_len)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+
+ /* read the environment variables */
+ environ = apr_pcalloc(r->pool, (req->env_count + 2) *sizeof(char *));
+ for (i = 0; i < req->env_count; i++) {
+ apr_size_t curlen;
+
+ if ((stat = sock_read(fd, &curlen, sizeof(curlen))) != APR_SUCCESS) {
+ return stat;
+ }
+ environ[i] = apr_pcalloc(r->pool, curlen + 1);
+ if ((stat = sock_read(fd, environ[i], curlen)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+ *env = environ;
+
+#ifdef AP_CGID_USE_RLIMIT
+ if ((stat = sock_read(fd, &(req->limits), sizeof(cgid_rlimit_t))) != APR_SUCCESS)
+ return stat;
+#endif
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env,
+ int req_type)
+{
+ int i;
+ cgid_req_t req = {0};
+ apr_status_t stat;
+ ap_unix_identity_t * ugid = ap_run_get_suexec_identity(r);
+ core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config);
+
+
+ if (ugid == NULL) {
+ req.ugid = empty_ugid;
+ } else {
+ memcpy(&req.ugid, ugid, sizeof(ap_unix_identity_t));
+ }
+
+ req.req_type = req_type;
+ req.ppid = parent_pid;
+ req.conn_id = r->connection->id;
+ for (req.env_count = 0; env[req.env_count]; req.env_count++) {
+ continue;
+ }
+ req.filename_len = strlen(r->filename);
+ req.argv0_len = strlen(argv0);
+ req.uri_len = strlen(r->uri);
+ req.args_len = r->args ? strlen(r->args) : 0;
+ req.loglevel = r->server->log.level;
+
+ /* Write the request header */
+ if (req.args_len) {
+ stat = sock_writev(fd, r, 5,
+ &req, sizeof(req),
+ r->filename, req.filename_len,
+ argv0, req.argv0_len,
+ r->uri, req.uri_len,
+ r->args, req.args_len);
+ } else {
+ stat = sock_writev(fd, r, 4,
+ &req, sizeof(req),
+ r->filename, req.filename_len,
+ argv0, req.argv0_len,
+ r->uri, req.uri_len);
+ }
+
+ if (stat != APR_SUCCESS) {
+ return stat;
+ }
+
+ /* write the environment variables */
+ for (i = 0; i < req.env_count; i++) {
+ apr_size_t curlen = strlen(env[i]);
+
+ if ((stat = sock_writev(fd, r, 2, &curlen, sizeof(curlen),
+ env[i], curlen)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+#if defined(RLIMIT_CPU) && defined(AP_CGID_USE_RLIMIT)
+ if (core_conf->limit_cpu) {
+ req.limits.limit_cpu = *(core_conf->limit_cpu);
+ req.limits.limit_cpu_set = 1;
+ }
+ else {
+ req.limits.limit_cpu_set = 0;
+ }
+#endif
+
+#if defined(AP_CGID_USE_RLIMIT) && (defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS))
+ if (core_conf->limit_mem) {
+ req.limits.limit_mem = *(core_conf->limit_mem);
+ req.limits.limit_mem_set = 1;
+ }
+ else {
+ req.limits.limit_mem_set = 0;
+ }
+
+#endif
+
+#if defined(RLIMIT_NPROC) && defined(AP_CGID_USE_RLIMIT)
+ if (core_conf->limit_nproc) {
+ req.limits.limit_nproc = *(core_conf->limit_nproc);
+ req.limits.limit_nproc_set = 1;
+ }
+ else {
+ req.limits.limit_nproc_set = 0;
+ }
+#endif
+
+#ifdef AP_CGID_USE_RLIMIT
+ if ( (stat = sock_write(fd, &(req.limits), sizeof(cgid_rlimit_t))) != APR_SUCCESS)
+ return stat;
+#endif
+
+ return APR_SUCCESS;
+}
+
+static void daemon_signal_handler(int sig)
+{
+ if (sig == SIGHUP) {
+ ++daemon_should_exit;
+ }
+}
+
+static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err,
+ const char *description)
+{
+ request_rec *r;
+ void *vr;
+
+ apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool);
+ r = vr;
+
+ /* sure we got r, but don't call ap_log_rerror() because we don't
+ * have r->headers_in and possibly other storage referenced by
+ * ap_log_rerror()
+ */
+ ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description);
+}
+
+static int cgid_server(void *data)
+{
+ int sd, sd2, rc;
+ mode_t omask;
+ apr_pool_t *ptrans;
+ server_rec *main_server = data;
+ apr_hash_t *script_hash = apr_hash_make(pcgi);
+ apr_status_t rv;
+
+ apr_pool_create(&ptrans, pcgi);
+
+ apr_signal(SIGCHLD, SIG_IGN);
+ apr_signal(SIGHUP, daemon_signal_handler);
+
+ /* Close our copy of the listening sockets */
+ ap_close_listeners();
+
+ /* cgid should use its own suexec doer */
+ ap_hook_get_suexec_identity(cgid_suexec_id_doer, NULL, NULL,
+ APR_HOOK_REALLY_FIRST);
+ apr_hook_sort_all();
+
+ if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01242)
+ "Couldn't create unix domain socket");
+ return errno;
+ }
+
+ omask = umask(0077); /* so that only Apache can use socket */
+ rc = bind(sd, (struct sockaddr *)server_addr, server_addr_len);
+ umask(omask); /* can't fail, so can't clobber errno */
+ if (rc < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01243)
+ "Couldn't bind unix domain socket %s",
+ sockname);
+ return errno;
+ }
+
+ /* Not all flavors of unix use the current umask for AF_UNIX perms */
+ rv = apr_file_perms_set(sockname, APR_FPROT_UREAD|APR_FPROT_UWRITE|APR_FPROT_UEXECUTE);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, main_server, APLOGNO(01244)
+ "Couldn't set permissions on unix domain socket %s",
+ sockname);
+ return rv;
+ }
+
+ if (listen(sd, DEFAULT_CGID_LISTENBACKLOG) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01245)
+ "Couldn't listen on unix domain socket");
+ return errno;
+ }
+
+ if (!geteuid()) {
+ if (chown(sockname, ap_unixd_config.user_id, -1) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01246)
+ "Couldn't change owner of unix domain socket %s",
+ sockname);
+ return errno;
+ }
+ }
+
+ apr_pool_cleanup_register(pcgi, (void *)((long)sd),
+ close_unix_socket, close_unix_socket);
+
+ /* if running as root, switch to configured user/group */
+ if ((rc = ap_run_drop_privileges(pcgi, ap_server_conf)) != 0) {
+ return rc;
+ }
+
+ while (!daemon_should_exit) {
+ int errfileno = STDERR_FILENO;
+ char *argv0 = NULL;
+ char **env = NULL;
+ const char * const *argv;
+ apr_int32_t in_pipe;
+ apr_int32_t out_pipe;
+ apr_int32_t err_pipe;
+ apr_cmdtype_e cmd_type;
+ request_rec *r;
+ apr_procattr_t *procattr = NULL;
+ apr_proc_t *procnew = NULL;
+ apr_file_t *inout;
+ cgid_req_t cgid_req;
+ apr_status_t stat;
+ void *key;
+ apr_socklen_t len;
+ struct sockaddr_un unix_addr;
+
+ apr_pool_clear(ptrans);
+
+ len = sizeof(unix_addr);
+ sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
+ if (sd2 < 0) {
+#if defined(ENETDOWN)
+ if (errno == ENETDOWN) {
+ /* The network has been shut down, no need to continue. Die gracefully */
+ ++daemon_should_exit;
+ }
+#endif
+ if (errno != EINTR) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno,
+ (server_rec *)data, APLOGNO(01247)
+ "Error accepting on cgid socket");
+ }
+ continue;
+ }
+
+ r = apr_pcalloc(ptrans, sizeof(request_rec));
+ procnew = apr_pcalloc(ptrans, sizeof(*procnew));
+ r->pool = ptrans;
+ stat = get_req(sd2, r, &argv0, &env, &cgid_req);
+ if (stat != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, stat,
+ main_server, APLOGNO(01248)
+ "Error reading request on cgid socket");
+ close(sd2);
+ continue;
+ }
+
+ if (cgid_req.ppid != parent_pid) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, 0, main_server, APLOGNO(01249)
+ "CGI request received from wrong server instance; "
+ "see ScriptSock directive");
+ close(sd2);
+ continue;
+ }
+
+ if (cgid_req.req_type == GETPID_REQ) {
+ pid_t pid;
+ apr_status_t rv;
+
+ pid = (pid_t)((long)apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id)));
+ rv = sock_write(sd2, &pid, sizeof(pid));
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
+ main_server, APLOGNO(01250)
+ "Error writing pid %" APR_PID_T_FMT " to handler", pid);
+ }
+ close(sd2);
+ continue;
+ }
+
+ apr_os_file_put(&r->server->error_log, &errfileno, 0, r->pool);
+ apr_os_file_put(&inout, &sd2, 0, r->pool);
+
+ if (cgid_req.req_type == SSI_REQ) {
+ in_pipe = APR_NO_PIPE;
+ out_pipe = APR_FULL_BLOCK;
+ err_pipe = APR_NO_PIPE;
+ cmd_type = APR_SHELLCMD;
+ }
+ else {
+ in_pipe = APR_CHILD_BLOCK;
+ out_pipe = APR_CHILD_BLOCK;
+ err_pipe = APR_CHILD_BLOCK;
+ cmd_type = APR_PROGRAM;
+ }
+
+ if (((rc = apr_procattr_create(&procattr, ptrans)) != APR_SUCCESS) ||
+ ((cgid_req.req_type == CGI_REQ) &&
+ (((rc = apr_procattr_io_set(procattr,
+ in_pipe,
+ out_pipe,
+ err_pipe)) != APR_SUCCESS) ||
+ /* XXX apr_procattr_child_*_set() is creating an unnecessary
+ * pipe between this process and the child being created...
+ * It is cleaned up with the temporary pool for this request.
+ */
+ ((rc = apr_procattr_child_err_set(procattr, r->server->error_log, NULL)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_child_in_set(procattr, inout, NULL)) != APR_SUCCESS))) ||
+ ((rc = apr_procattr_child_out_set(procattr, inout, NULL)) != APR_SUCCESS) ||
+ ((rc = apr_procattr_dir_set(procattr,
+ ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) ||
+ ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS) ||
+#ifdef AP_CGID_USE_RLIMIT
+#ifdef RLIMIT_CPU
+ ( (cgid_req.limits.limit_cpu_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU,
+ &cgid_req.limits.limit_cpu)) != APR_SUCCESS)) ||
+#endif
+#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
+ ( (cgid_req.limits.limit_mem_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM,
+ &cgid_req.limits.limit_mem)) != APR_SUCCESS)) ||
+#endif
+#ifdef RLIMIT_NPROC
+ ( (cgid_req.limits.limit_nproc_set) && ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC,
+ &cgid_req.limits.limit_nproc)) != APR_SUCCESS)) ||
+#endif
+#endif
+
+ ((rc = apr_procattr_child_errfn_set(procattr, cgid_child_errfn)) != APR_SUCCESS)) {
+ /* Something bad happened, tell the world.
+ * ap_log_rerror() won't work because the header table used by
+ * ap_log_rerror() hasn't been replicated in the phony r
+ */
+ ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01251)
+ "couldn't set child process attributes: %s", r->filename);
+
+ procnew->pid = 0; /* no process to clean up */
+ close(sd2);
+ }
+ else {
+ apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans);
+
+ argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args);
+
+ /* We want to close sd2 for the new CGI process too.
+ * If it is left open it'll make ap_pass_brigade() block
+ * waiting for EOF if CGI forked something running long.
+ * close(sd2) here should be okay, as CGI channel
+ * is already dup()ed by apr_procattr_child_{in,out}_set()
+ * above.
+ */
+ close(sd2);
+
+ if (memcmp(&empty_ugid, &cgid_req.ugid, sizeof(empty_ugid))) {
+ /* We have a valid identity, and can be sure that
+ * cgid_suexec_id_doer will return a valid ugid
+ */
+ rc = ap_os_create_privileged_process(r, procnew, argv0, argv,
+ (const char * const *)env,
+ procattr, ptrans);
+ } else {
+ rc = apr_proc_create(procnew, argv0, argv,
+ (const char * const *)env,
+ procattr, ptrans);
+ }
+
+ if (rc != APR_SUCCESS) {
+ /* Bad things happened. Everyone should have cleaned up.
+ * ap_log_rerror() won't work because the header table used by
+ * ap_log_rerror() hasn't been replicated in the phony r
+ */
+ ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01252)
+ "couldn't create child process: %d: %s", rc,
+ apr_filepath_name_get(r->filename));
+
+ procnew->pid = 0; /* no process to clean up */
+ }
+ }
+
+ /* If the script process was created, remember the pid for
+ * later cleanup. If the script process wasn't created, clear
+ * out any prior pid with the same key.
+ *
+ * We don't want to leak storage for the key, so only allocate
+ * a key if the key doesn't exist yet in the hash; there are
+ * only a limited number of possible keys (one for each
+ * possible thread in the server), so we can allocate a copy
+ * of the key the first time a thread has a cgid request.
+ * Note that apr_hash_set() only uses the storage passed in
+ * for the key if it is adding the key to the hash for the
+ * first time; new key storage isn't needed for replacing the
+ * existing value of a key.
+ */
+
+ if (apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id))) {
+ key = &cgid_req.conn_id;
+ }
+ else {
+ key = apr_pmemdup(pcgi, &cgid_req.conn_id, sizeof(cgid_req.conn_id));
+ }
+ apr_hash_set(script_hash, key, sizeof(cgid_req.conn_id),
+ (void *)((long)procnew->pid));
+ }
+ return -1; /* should be <= 0 to distinguish from startup errors */
+}
+
+static int cgid_start(apr_pool_t *p, server_rec *main_server,
+ apr_proc_t *procnew)
+{
+
+ daemon_should_exit = 0; /* clear setting from previous generation */
+ if ((daemon_pid = fork()) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server, APLOGNO(01253)
+ "mod_cgid: Couldn't spawn cgid daemon process");
+ return DECLINED;
+ }
+ else if (daemon_pid == 0) {
+ if (pcgi == NULL) {
+ apr_pool_create(&pcgi, p);
+ }
+ exit(cgid_server(main_server) > 0 ? DAEMON_STARTUP_ERROR : -1);
+ }
+ procnew->pid = daemon_pid;
+ procnew->err = procnew->in = procnew->out = NULL;
+ apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
+#if APR_HAS_OTHER_CHILD
+ apr_proc_other_child_register(procnew, cgid_maint, procnew, NULL, p);
+#endif
+ return OK;
+}
+
+static int cgid_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
+ apr_pool_t *ptemp)
+{
+ sockname = ap_append_pid(pconf, DEFAULT_SOCKET, ".");
+ return OK;
+}
+
+static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
+ server_rec *main_server)
+{
+ apr_proc_t *procnew = NULL;
+ const char *userdata_key = "cgid_init";
+ int ret = OK;
+ void *data;
+
+ root_server = main_server;
+ root_pool = p;
+
+ apr_pool_userdata_get(&data, userdata_key, main_server->process->pool);
+ if (!data) {
+ procnew = apr_pcalloc(main_server->process->pool, sizeof(*procnew));
+ procnew->pid = -1;
+ procnew->err = procnew->in = procnew->out = NULL;
+ apr_pool_userdata_set((const void *)procnew, userdata_key,
+ apr_pool_cleanup_null, main_server->process->pool);
+ return ret;
+ }
+ else {
+ procnew = data;
+ }
+
+ if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) {
+ char *tmp_sockname;
+
+ parent_pid = getpid();
+ tmp_sockname = ap_runtime_dir_relative(p, sockname);
+ if (strlen(tmp_sockname) > sizeof(server_addr->sun_path) - 1) {
+ tmp_sockname[sizeof(server_addr->sun_path)] = '\0';
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server, APLOGNO(01254)
+ "The length of the ScriptSock path exceeds maximum, "
+ "truncating to %s", tmp_sockname);
+ }
+ sockname = tmp_sockname;
+
+ server_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) + strlen(sockname);
+ server_addr = (struct sockaddr_un *)apr_palloc(p, server_addr_len + 1);
+ server_addr->sun_family = AF_UNIX;
+ strcpy(server_addr->sun_path, sockname);
+
+ ret = cgid_start(p, main_server, procnew);
+ if (ret != OK ) {
+ return ret;
+ }
+ cgid_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
+ cgid_pfn_gtv = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
+ cgid_pfn_ps = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
+
+ if ((cgid_pfn_reg_with_ssi) && (cgid_pfn_gtv) && (cgid_pfn_ps)) {
+ /* Required by mod_include filter. This is how mod_cgid registers
+ * with mod_include to provide processing of the exec directive.
+ */
+ cgid_pfn_reg_with_ssi("exec", handle_exec);
+ }
+ }
+ return ret;
+}
+
+static void *create_cgid_config(apr_pool_t *p, server_rec *s)
+{
+ cgid_server_conf *c =
+ (cgid_server_conf *) apr_pcalloc(p, sizeof(cgid_server_conf));
+
+ c->logname = NULL;
+ c->logbytes = DEFAULT_LOGBYTES;
+ c->bufbytes = DEFAULT_BUFBYTES;
+ return c;
+}
+
+static void *merge_cgid_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+ cgid_server_conf *base = (cgid_server_conf *) basev, *overrides = (cgid_server_conf *) overridesv;
+
+ return overrides->logname ? overrides : base;
+}
+
+static void *create_cgid_dirconf(apr_pool_t *p, char *dummy)
+{
+ cgid_dirconf *c = (cgid_dirconf *) apr_pcalloc(p, sizeof(cgid_dirconf));
+ return c;
+}
+
+static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
+
+{
+ server_rec *s = cmd->server;
+ cgid_server_conf *conf = ap_get_module_config(s->module_config,
+ &cgid_module);
+
+ conf->logname = ap_server_root_relative(cmd->pool, arg);
+
+ if (!conf->logname) {
+ return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",
+ arg, NULL);
+ }
+ return NULL;
+}
+
+static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ server_rec *s = cmd->server;
+ cgid_server_conf *conf = ap_get_module_config(s->module_config,
+ &cgid_module);
+
+ conf->logbytes = atol(arg);
+ return NULL;
+}
+
+static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ server_rec *s = cmd->server;
+ cgid_server_conf *conf = ap_get_module_config(s->module_config,
+ &cgid_module);
+
+ conf->bufbytes = atoi(arg);
+ return NULL;
+}
+
+static const char *set_script_socket(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ /* Make sure the pid is appended to the sockname */
+ sockname = ap_append_pid(cmd->pool, arg, ".");
+ sockname = ap_runtime_dir_relative(cmd->pool, sockname);
+
+ if (!sockname) {
+ return apr_pstrcat(cmd->pool, "Invalid ScriptSock path",
+ arg, NULL);
+ }
+
+ return NULL;
+}
+static const char *set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ cgid_dirconf *dc = dummy;
+
+ if (ap_timeout_parameter_parse(arg, &dc->timeout, "s") != APR_SUCCESS) {
+ return "CGIDScriptTimeout has wrong format";
+ }
+
+ return NULL;
+}
+static const command_rec cgid_cmds[] =
+{
+ AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF,
+ "the name of a log for script debugging info"),
+ AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,
+ "the maximum length (in bytes) of the script debug log"),
+ AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,
+ "the maximum size (in bytes) to record of a POST request"),
+ AP_INIT_TAKE1("ScriptSock", set_script_socket, NULL, RSRC_CONF,
+ "the name of the socket to use for communication with "
+ "the cgi daemon."),
+ AP_INIT_TAKE1("CGIDScriptTimeout", set_script_timeout, NULL, RSRC_CONF | ACCESS_CONF,
+ "The amount of time to wait between successful reads from "
+ "the CGI script, in seconds."),
+
+ {NULL}
+};
+
+static int log_scripterror(request_rec *r, cgid_server_conf * conf, int ret,
+ apr_status_t rv, char *error)
+{
+ apr_file_t *f = NULL;
+ struct stat finfo;
+ char time_str[APR_CTIME_LEN];
+ int log_flags = rv ? APLOG_ERR : APLOG_ERR;
+
+ /* Intentional no APLOGNO */
+ /* Callee provides APLOGNO in error text */
+ ap_log_rerror(APLOG_MARK, log_flags, rv, r,
+ "%s: %s", error, r->filename);
+
+ /* XXX Very expensive mainline case! Open, then getfileinfo! */
+ if (!conf->logname ||
+ ((stat(conf->logname, &finfo) == 0)
+ && (finfo.st_size > conf->logbytes)) ||
+ (apr_file_open(&f, conf->logname,
+ APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {
+ return ret;
+ }
+
+ /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
+ apr_ctime(time_str, apr_time_now());
+ apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
+ r->args ? "?" : "", r->args ? r->args : "", r->protocol);
+ /* "%% 500 /usr/local/apache/cgid-bin */
+ apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
+
+ apr_file_printf(f, "%%error\n%s\n", error);
+
+ apr_file_close(f);
+ return ret;
+}
+
+static int log_script(request_rec *r, cgid_server_conf * conf, int ret,
+ char *dbuf, const char *sbuf, apr_bucket_brigade *bb,
+ apr_file_t *script_err)
+{
+ const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);
+ const apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
+ char argsbuffer[HUGE_STRING_LEN];
+ apr_file_t *f = NULL;
+ apr_bucket *e;
+ const char *buf;
+ apr_size_t len;
+ apr_status_t rv;
+ int first;
+ int i;
+ struct stat finfo;
+ char time_str[APR_CTIME_LEN];
+
+ /* XXX Very expensive mainline case! Open, then getfileinfo! */
+ if (!conf->logname ||
+ ((stat(conf->logname, &finfo) == 0)
+ && (finfo.st_size > conf->logbytes)) ||
+ (apr_file_open(&f, conf->logname,
+ APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {
+ /* Soak up script output */
+ discard_script_output(bb);
+ if (script_err) {
+ while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
+ script_err) == APR_SUCCESS)
+ continue;
+ }
+ return ret;
+ }
+
+ /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
+ apr_ctime(time_str, apr_time_now());
+ apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
+ r->args ? "?" : "", r->args ? r->args : "", r->protocol);
+ /* "%% 500 /usr/local/apache/cgid-bin" */
+ apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
+
+ apr_file_puts("%request\n", f);
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (!hdrs[i].key)
+ continue;
+ apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
+ }
+ if ((r->method_number == M_POST || r->method_number == M_PUT)
+ && *dbuf) {
+ apr_file_printf(f, "\n%s\n", dbuf);
+ }
+
+ apr_file_puts("%response\n", f);
+ hdrs_arr = apr_table_elts(r->err_headers_out);
+ hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
+
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (!hdrs[i].key)
+ continue;
+ apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
+ }
+
+ if (sbuf && *sbuf)
+ apr_file_printf(f, "%s\n", sbuf);
+
+ first = 1;
+
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ if (APR_BUCKET_IS_EOS(e)) {
+ break;
+ }
+ rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
+ if (rv != APR_SUCCESS || (len == 0)) {
+ break;
+ }
+ if (first) {
+ apr_file_puts("%stdout\n", f);
+ first = 0;
+ }
+ apr_file_write_full(f, buf, len, NULL);
+ apr_file_puts("\n", f);
+ }
+
+ if (script_err) {
+ if (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
+ script_err) == APR_SUCCESS) {
+ apr_file_puts("%stderr\n", f);
+ apr_file_puts(argsbuffer, f);
+ while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
+ script_err) == APR_SUCCESS)
+ apr_file_puts(argsbuffer, f);
+ apr_file_puts("\n", f);
+ }
+ }
+
+ if (script_err) {
+ apr_file_close(script_err);
+ }
+
+ apr_file_close(f);
+ return ret;
+}
+
+static int connect_to_daemon(int *sdptr, request_rec *r,
+ cgid_server_conf *conf)
+{
+ int sd;
+ int connect_tries;
+ int connect_errno;
+ apr_interval_time_t sliding_timer;
+
+ connect_tries = 0;
+ sliding_timer = 100000; /* 100 milliseconds */
+ while (1) {
+ connect_errno = 0;
+ ++connect_tries;
+ if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno,
+ APLOGNO(01255) "unable to create socket to cgi daemon");
+ }
+ if (connect(sd, (struct sockaddr *)server_addr, server_addr_len) < 0) {
+ /* Save errno for later */
+ connect_errno = errno;
+ /* ECONNREFUSED means the listen queue is full; ENOENT means that
+ * the cgid server either hasn't started up yet, or we're pointing
+ * at the wrong socket file */
+ if ((errno == ECONNREFUSED || errno == ENOENT) &&
+ connect_tries < DEFAULT_CONNECT_ATTEMPTS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r, APLOGNO(01256)
+ "connect #%d to cgi daemon failed, sleeping before retry",
+ connect_tries);
+ close(sd);
+ apr_sleep(sliding_timer);
+ if (sliding_timer < apr_time_from_sec(2)) {
+ sliding_timer *= 2;
+ }
+ }
+ else {
+ close(sd);
+ return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno, APLOGNO(01257)
+ "unable to connect to cgi daemon after multiple tries");
+ }
+ }
+ else {
+ apr_pool_cleanup_register(r->pool, (void *)((long)sd),
+ close_unix_socket, apr_pool_cleanup_null);
+ break; /* we got connected! */
+ }
+
+ /* If we didn't find the socket but the server was not recently restarted,
+ * chances are there's something wrong with the cgid daemon
+ */
+ if (connect_errno == ENOENT &&
+ apr_time_sec(apr_time_now() - ap_scoreboard_image->global->restart_time) >
+ DEFAULT_CONNECT_STARTUP_DELAY) {
+ return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, connect_errno,
+ apr_pstrcat(r->pool, APLOGNO(02833) "ScriptSock ", sockname, " does not exist", NULL));
+ }
+
+ /* gotta try again, but make sure the cgid daemon is still around */
+ if (connect_errno != ENOENT && kill(daemon_pid, 0) != 0) {
+ return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, connect_errno, APLOGNO(01258)
+ "cgid daemon is gone; is Apache terminating?");
+ }
+ }
+ *sdptr = sd;
+ return OK;
+}
+
+static void discard_script_output(apr_bucket_brigade *bb)
+{
+ apr_bucket *e;
+ const char *buf;
+ apr_size_t len;
+ apr_status_t rv;
+
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ if (APR_BUCKET_IS_EOS(e)) {
+ break;
+ }
+ rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
+ if (rv != APR_SUCCESS) {
+ break;
+ }
+ }
+}
+
+/****************************************************************
+ *
+ * Actual cgid handling...
+ */
+
+struct cleanup_script_info {
+ request_rec *r;
+ cgid_server_conf *conf;
+ pid_t pid;
+};
+
+static apr_status_t dead_yet(pid_t pid, apr_interval_time_t max_wait)
+{
+ apr_interval_time_t interval = 10000; /* 10 ms */
+ apr_interval_time_t total = 0;
+
+ do {
+#ifdef _AIX
+ /* On AIX, for processes like mod_cgid's script children where
+ * SIGCHLD is ignored, kill(pid,0) returns success for up to
+ * one second after the script child exits, based on when a
+ * daemon runs to clean up unnecessary process table entries.
+ * getpgid() can report the proper info (-1/ESRCH) immediately.
+ */
+ if (getpgid(pid) < 0) {
+#else
+ if (kill(pid, 0) < 0) {
+#endif
+ return APR_SUCCESS;
+ }
+ apr_sleep(interval);
+ total = total + interval;
+ if (interval < 500000) {
+ interval *= 2;
+ }
+ } while (total < max_wait);
+ return APR_EGENERAL;
+}
+
+static apr_status_t cleanup_nonchild_process(request_rec *r, pid_t pid)
+{
+ kill(pid, SIGTERM); /* in case it isn't dead yet */
+ if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {
+ return APR_SUCCESS;
+ }
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01259)
+ "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL",
+ pid);
+ kill(pid, SIGKILL);
+ if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {
+ return APR_SUCCESS;
+ }
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01260)
+ "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL again",
+ pid);
+ kill(pid, SIGKILL);
+
+ return APR_EGENERAL;
+}
+
+static apr_status_t get_cgi_pid(request_rec *r, cgid_server_conf *conf, pid_t *pid) {
+ cgid_req_t req = {0};
+ apr_status_t stat;
+ int rc, sd;
+
+ rc = connect_to_daemon(&sd, r, conf);
+ if (rc != OK) {
+ return APR_EGENERAL;
+ }
+
+ req.req_type = GETPID_REQ;
+ req.ppid = parent_pid;
+ req.conn_id = r->connection->id;
+
+ stat = sock_write(sd, &req, sizeof(req));
+ if (stat != APR_SUCCESS) {
+ return stat;
+ }
+
+ /* wait for pid of script */
+ stat = sock_read(sd, pid, sizeof(*pid));
+ if (stat != APR_SUCCESS) {
+ return stat;
+ }
+
+ if (pid == 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01261)
+ "daemon couldn't find CGI process for connection %lu",
+ r->connection->id);
+ return APR_EGENERAL;
+ }
+
+ return APR_SUCCESS;
+}
+
+
+static apr_status_t cleanup_script(void *vptr)
+{
+ struct cleanup_script_info *info = vptr;
+ return cleanup_nonchild_process(info->r, info->pid);
+}
+
+static int cgid_handler(request_rec *r)
+{
+ int retval, nph, dbpos;
+ char *argv0, *dbuf;
+ apr_bucket_brigade *bb;
+ apr_bucket *b;
+ cgid_server_conf *conf;
+ int is_included;
+ int seen_eos, child_stopped_reading;
+ int sd;
+ char **env;
+ apr_file_t *tempsock;
+ struct cleanup_script_info *info;
+ apr_status_t rv;
+ cgid_dirconf *dc;
+
+ if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) {
+ return DECLINED;
+ }
+
+ conf = ap_get_module_config(r->server->module_config, &cgid_module);
+ dc = ap_get_module_config(r->per_dir_config, &cgid_module);
+
+
+ is_included = !strcmp(r->protocol, "INCLUDED");
+
+ if ((argv0 = strrchr(r->filename, '/')) != NULL) {
+ argv0++;
+ }
+ else {
+ argv0 = r->filename;
+ }
+
+ nph = !(strncmp(argv0, "nph-", 4));
+
+ argv0 = r->filename;
+
+ if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) {
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01262)
+ "Options ExecCGI is off in this directory");
+ }
+
+ if (nph && is_included) {
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01263)
+ "attempt to include NPH CGI script");
+ }
+
+#if defined(OS2) || defined(WIN32)
+#error mod_cgid does not work on this platform. If you teach it to, look
+#error at mod_cgi.c for required code in this path.
+#else
+ if (r->finfo.filetype == APR_NOFILE) {
+ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01264)
+ "script not found or unable to stat");
+ }
+#endif
+ if (r->finfo.filetype == APR_DIR) {
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01265)
+ "attempt to invoke directory as script");
+ }
+
+ if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) &&
+ r->path_info && *r->path_info)
+ {
+ /* default to accept */
+ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(01266)
+ "AcceptPathInfo off disallows user's path");
+ }
+ /*
+ if (!ap_suexec_enabled) {
+ if (!ap_can_exec(&r->finfo))
+ return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(01267)
+ "file permissions deny server execution");
+ }
+ */
+
+ /*
+ * httpd core function used to add common environment variables like
+ * DOCUMENT_ROOT.
+ */
+ ap_add_common_vars(r);
+ ap_add_cgi_vars(r);
+ env = ap_create_environment(r->pool, r->subprocess_env);
+
+ if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
+ return retval;
+ }
+
+ rv = send_req(sd, r, argv0, env, CGI_REQ);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01268)
+ "write to cgi daemon process");
+ }
+
+ info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
+ info->conf = conf;
+ info->r = r;
+ rv = get_cgi_pid(r, conf, &(info->pid));
+
+ if (APR_SUCCESS == rv){
+ apr_pool_cleanup_register(r->pool, info,
+ cleanup_script,
+ apr_pool_cleanup_null);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "error determining cgi PID");
+ }
+
+ /* We are putting the socket discriptor into an apr_file_t so that we can
+ * use a pipe bucket to send the data to the client. APR will create
+ * a cleanup for the apr_file_t which will close the socket, so we'll
+ * get rid of the cleanup we registered when we created the socket.
+ */
+
+ apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
+ if (dc->timeout > 0) {
+ apr_file_pipe_timeout_set(tempsock, dc->timeout);
+ }
+ else {
+ apr_file_pipe_timeout_set(tempsock, r->server->timeout);
+ }
+ apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);
+
+ /* Transfer any put/post args, CERN style...
+ * Note that we already ignore SIGPIPE in the core server.
+ */
+ bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ seen_eos = 0;
+ child_stopped_reading = 0;
+ dbuf = NULL;
+ dbpos = 0;
+ if (conf->logname) {
+ dbuf = apr_palloc(r->pool, conf->bufbytes + 1);
+ }
+ do {
+ apr_bucket *bucket;
+
+ rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
+ APR_BLOCK_READ, HUGE_STRING_LEN);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01270)
+ "Error reading request entity data");
+ return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
+ }
+
+ for (bucket = APR_BRIGADE_FIRST(bb);
+ bucket != APR_BRIGADE_SENTINEL(bb);
+ bucket = APR_BUCKET_NEXT(bucket))
+ {
+ const char *data;
+ apr_size_t len;
+
+ if (APR_BUCKET_IS_EOS(bucket)) {
+ seen_eos = 1;
+ break;
+ }
+
+ /* We can't do much with this. */
+ if (APR_BUCKET_IS_FLUSH(bucket)) {
+ continue;
+ }
+
+ /* If the child stopped, we still must read to EOS. */
+ if (child_stopped_reading) {
+ continue;
+ }
+
+ /* read */
+ apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
+
+ if (conf->logname && dbpos < conf->bufbytes) {
+ int cursize;
+
+ if ((dbpos + len) > conf->bufbytes) {
+ cursize = conf->bufbytes - dbpos;
+ }
+ else {
+ cursize = len;
+ }
+ memcpy(dbuf + dbpos, data, cursize);
+ dbpos += cursize;
+ }
+
+ /* Keep writing data to the child until done or too much time
+ * elapses with no progress or an error occurs.
+ */
+ rv = apr_file_write_full(tempsock, data, len, NULL);
+
+ if (rv != APR_SUCCESS) {
+ /* silly script stopped reading, soak up remaining message */
+ child_stopped_reading = 1;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02651)
+ "Error writing request body to script %s",
+ r->filename);
+
+ }
+ }
+ apr_brigade_cleanup(bb);
+ }
+ while (!seen_eos);
+
+ if (conf->logname) {
+ dbuf[dbpos] = '\0';
+ }
+
+ /* we're done writing, or maybe we didn't write at all;
+ * force EOF on child's stdin so that the cgi detects end (or
+ * absence) of data
+ */
+ shutdown(sd, 1);
+
+ /* Handle script return... */
+ if (!nph) {
+ conn_rec *c = r->connection;
+ const char *location;
+ char sbuf[MAX_STRING_LEN];
+ int ret;
+
+ bb = apr_brigade_create(r->pool, c->bucket_alloc);
+ b = apr_bucket_pipe_create(tempsock, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ b = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+
+ if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
+ APLOG_MODULE_INDEX)))
+ {
+ ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL);
+
+ /*
+ * ret could be HTTP_NOT_MODIFIED in the case that the CGI script
+ * does not set an explicit status and ap_meets_conditions, which
+ * is called by ap_scan_script_header_err_brigade, detects that
+ * the conditions of the requests are met and the response is
+ * not modified.
+ * In this case set r->status and return OK in order to prevent
+ * running through the error processing stack as this would
+ * break with mod_cache, if the conditions had been set by
+ * mod_cache itself to validate a stale entity.
+ * BTW: We circumvent the error processing stack anyway if the
+ * CGI script set an explicit status code (whatever it is) and
+ * the only possible values for ret here are:
+ *
+ * HTTP_NOT_MODIFIED (set by ap_meets_conditions)
+ * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions)
+ * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the
+ * processing of the response of the CGI script, e.g broken headers
+ * or a crashed CGI process).
+ */
+ if (ret == HTTP_NOT_MODIFIED) {
+ r->status = ret;
+ return OK;
+ }
+
+ return ret;
+ }
+
+ location = apr_table_get(r->headers_out, "Location");
+
+ if (location && location[0] == '/' && r->status == 200) {
+
+ /* Soak up all the script output */
+ discard_script_output(bb);
+ apr_brigade_destroy(bb);
+ /* This redirect needs to be a GET no matter what the original
+ * method was.
+ */
+ r->method = "GET";
+ r->method_number = M_GET;
+
+ /* We already read the message body (if any), so don't allow
+ * the redirected request to think it has one. We can ignore
+ * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
+ */
+ apr_table_unset(r->headers_in, "Content-Length");
+
+ ap_internal_redirect_handler(location, r);
+ return OK;
+ }
+ else if (location && r->status == 200) {
+ /* XXX: Note that if a script wants to produce its own Redirect
+ * body, it now has to explicitly *say* "Status: 302"
+ */
+ discard_script_output(bb);
+ apr_brigade_destroy(bb);
+ return HTTP_MOVED_TEMPORARILY;
+ }
+
+ rv = ap_pass_brigade(r->output_filters, bb);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
+ "Failed to flush CGI output to client");
+ }
+ }
+
+ if (nph) {
+ conn_rec *c = r->connection;
+ struct ap_filter_t *cur;
+
+ /* get rid of all filters up through protocol... since we
+ * haven't parsed off the headers, there is no way they can
+ * work
+ */
+
+ cur = r->proto_output_filters;
+ while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
+ cur = cur->next;
+ }
+ r->output_filters = r->proto_output_filters = cur;
+
+ bb = apr_brigade_create(r->pool, c->bucket_alloc);
+ b = apr_bucket_pipe_create(tempsock, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ b = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ ap_pass_brigade(r->output_filters, bb);
+ }
+
+ return OK; /* NOT r->status, even if it has changed. */
+}
+
+
+
+
+/*============================================================================
+ *============================================================================
+ * This is the beginning of the cgi filter code moved from mod_include. This
+ * is the code required to handle the "exec" SSI directive.
+ *============================================================================
+ *============================================================================*/
+static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *bb, char *s)
+{
+ request_rec *r = f->r;
+ request_rec *rr = ap_sub_req_lookup_uri(s, r, f->next);
+ int rr_status;
+
+ if (rr->status != HTTP_OK) {
+ ap_destroy_sub_req(rr);
+ return APR_EGENERAL;
+ }
+
+ /* No hardwired path info or query allowed */
+ if ((rr->path_info && rr->path_info[0]) || rr->args) {
+ ap_destroy_sub_req(rr);
+ return APR_EGENERAL;
+ }
+ if (rr->finfo.filetype != APR_REG) {
+ ap_destroy_sub_req(rr);
+ return APR_EGENERAL;
+ }
+
+ /* Script gets parameters of the *document*, for back compatibility */
+ rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */
+ rr->args = r->args;
+
+ /* Force sub_req to be treated as a CGI request, even if ordinary
+ * typing rules would have called it something else.
+ */
+ ap_set_content_type(rr, CGI_MAGIC_TYPE);
+
+ /* Run it. */
+ rr_status = ap_run_sub_req(rr);
+ if (ap_is_HTTP_REDIRECT(rr_status)) {
+ const char *location = apr_table_get(rr->headers_out, "Location");
+
+ if (location) {
+ char *buffer;
+
+ location = ap_escape_html(rr->pool, location);
+ buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">",
+ location, "</a>", NULL);
+
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buffer,
+ strlen(buffer), ctx->pool,
+ f->c->bucket_alloc));
+ }
+ }
+
+ ap_destroy_sub_req(rr);
+
+ return APR_SUCCESS;
+}
+
+/* This is the special environment used for running the "exec cmd="
+ * variety of SSI directives.
+ */
+static void add_ssi_vars(request_rec *r)
+{
+ apr_table_t *e = r->subprocess_env;
+
+ if (r->path_info && r->path_info[0] != '\0') {
+ request_rec *pa_req;
+
+ apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info));
+
+ pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, NULL);
+ if (pa_req->filename) {
+ apr_table_setn(e, "PATH_TRANSLATED",
+ apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL));
+ }
+ ap_destroy_sub_req(pa_req);
+ }
+
+ if (r->args) {
+ char *arg_copy = apr_pstrdup(r->pool, r->args);
+
+ apr_table_setn(e, "QUERY_STRING", r->args);
+ ap_unescape_url(arg_copy);
+ apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy));
+ }
+}
+
+static int include_cmd(include_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *bb, char *command)
+{
+ char **env;
+ int sd;
+ int retval;
+ apr_file_t *tempsock = NULL;
+ request_rec *r = f->r;
+ cgid_server_conf *conf = ap_get_module_config(r->server->module_config,
+ &cgid_module);
+ cgid_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgid_module);
+
+ struct cleanup_script_info *info;
+ apr_status_t rv;
+
+ add_ssi_vars(r);
+ env = ap_create_environment(r->pool, r->subprocess_env);
+
+ if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
+ return retval;
+ }
+
+ send_req(sd, r, command, env, SSI_REQ);
+
+ info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
+ info->conf = conf;
+ info->r = r;
+ rv = get_cgi_pid(r, conf, &(info->pid));
+ if (APR_SUCCESS == rv) {
+ /* for this type of request, the script is invoked through an
+ * intermediate shell process... cleanup_script is only able
+ * to knock out the shell process, not the actual script
+ */
+ apr_pool_cleanup_register(r->pool, info,
+ cleanup_script,
+ apr_pool_cleanup_null);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "error determining cgi PID (for SSI)");
+ }
+
+ apr_pool_cleanup_register(r->pool, info,
+ cleanup_script,
+ apr_pool_cleanup_null);
+
+ /* We are putting the socket discriptor into an apr_file_t so that we can
+ * use a pipe bucket to send the data to the client. APR will create
+ * a cleanup for the apr_file_t which will close the socket, so we'll
+ * get rid of the cleanup we registered when we created the socket.
+ */
+ apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
+ if (dc->timeout > 0) {
+ apr_file_pipe_timeout_set(tempsock, dc->timeout);
+ }
+ else {
+ apr_file_pipe_timeout_set(tempsock, r->server->timeout);
+ }
+
+ apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);
+
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pipe_create(tempsock,
+ f->c->bucket_alloc));
+ ctx->flush_now = 1;
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t handle_exec(include_ctx_t *ctx, ap_filter_t *f,
+ apr_bucket_brigade *bb)
+{
+ char *tag = NULL;
+ char *tag_val = NULL;
+ request_rec *r = f->r;
+ char *file = r->filename;
+ char parsed_string[MAX_STRING_LEN];
+
+ if (!ctx->argc) {
+ ap_log_rerror(APLOG_MARK,
+ (ctx->flags & SSI_FLAG_PRINTING)
+ ? APLOG_ERR : APLOG_WARNING,
+ 0, r, APLOGNO(03196)
+ "missing argument for exec element in %s", r->filename);
+ }
+
+ if (!(ctx->flags & SSI_FLAG_PRINTING)) {
+ return APR_SUCCESS;
+ }
+
+ if (!ctx->argc) {
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ return APR_SUCCESS;
+ }
+
+ if (ctx->flags & SSI_FLAG_NO_EXEC) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01271) "exec used but not allowed "
+ "in %s", r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ return APR_SUCCESS;
+ }
+
+ while (1) {
+ cgid_pfn_gtv(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
+ if (!tag || !tag_val) {
+ break;
+ }
+
+ if (!strcmp(tag, "cmd")) {
+ apr_status_t rv;
+
+ cgid_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string),
+ SSI_EXPAND_LEAVE_NAME);
+
+ rv = include_cmd(ctx, f, bb, parsed_string);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01272)
+ "execution failure for parameter \"%s\" "
+ "to tag exec in file %s", tag, r->filename);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ break;
+ }
+ }
+ else if (!strcmp(tag, "cgi")) {
+ apr_status_t rv;
+
+ cgid_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string),
+ SSI_EXPAND_DROP_NAME);
+
+ rv = include_cgi(ctx, f, bb, parsed_string);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01273) "invalid CGI ref "
+ "\"%s\" in %s", tag_val, file);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ break;
+ }
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01274) "unknown parameter "
+ "\"%s\" to tag exec in %s", tag, file);
+ SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
+ break;
+ }
+ }
+
+ return APR_SUCCESS;
+}
+/*============================================================================
+ *============================================================================
+ * This is the end of the cgi filter code moved from mod_include.
+ *============================================================================
+ *============================================================================*/
+
+
+static void register_hook(apr_pool_t *p)
+{
+ static const char * const aszPre[] = { "mod_include.c", NULL };
+
+ ap_hook_pre_config(cgid_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_post_config(cgid_init, aszPre, NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(cgid_handler, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+AP_DECLARE_MODULE(cgid) = {
+ STANDARD20_MODULE_STUFF,
+ create_cgid_dirconf, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ create_cgid_config, /* server config */
+ merge_cgid_config, /* merge server config */
+ cgid_cmds, /* command table */
+ register_hook /* register_handlers */
+};
+
diff --git a/modules/generators/mod_cgid.exp b/modules/generators/mod_cgid.exp
new file mode 100644
index 0000000..5f10d48
--- /dev/null
+++ b/modules/generators/mod_cgid.exp
@@ -0,0 +1 @@
+cgid_module
diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c
new file mode 100644
index 0000000..e5e63de
--- /dev/null
+++ b/modules/generators/mod_info.c
@@ -0,0 +1,1011 @@
+/* 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.
+ */
+
+/*
+ * Info Module. Display configuration information for the server and
+ * all included modules.
+ *
+ * <Location /server-info>
+ * SetHandler server-info
+ * </Location>
+ *
+ * GET /server-info - Returns full configuration page for server and all modules
+ * GET /server-info?server - Returns server configuration only
+ * GET /server-info?module_name - Returns configuration for a single module
+ * GET /server-info?list - Returns quick list of included modules
+ * GET /server-info?config - Returns full configuration
+ * GET /server-info?hooks - Returns a listing of the modules active for each hook
+ *
+ * Original Author:
+ * Rasmus Lerdorf <rasmus vex.net>, May 1996
+ *
+ * Modified By:
+ * Lou Langholtz <ldl usi.utah.edu>, July 1997
+ *
+ * Apache 2.0 Port:
+ * Ryan Morgan <rmorgan covalent.net>, August 2000
+ *
+ */
+
+
+#include "apr.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_version.h"
+#if APR_MAJOR_VERSION < 2
+#include "apu_version.h"
+#endif
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "http_protocol.h"
+#include "http_connection.h"
+#include "http_request.h"
+#include "util_script.h"
+#include "ap_mpm.h"
+#include "mpm_common.h"
+#include "ap_provider.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct
+{
+ const char *name; /* matching module name */
+ const char *info; /* additional info */
+} info_entry;
+
+typedef struct
+{
+ apr_array_header_t *more_info;
+} info_svr_conf;
+
+module AP_MODULE_DECLARE_DATA info_module;
+
+/* current file name when doing -DDUMP_CONFIG */
+const char *dump_config_fn_info;
+/* file handle when doing -DDUMP_CONFIG */
+apr_file_t *out = NULL;
+
+static void *create_info_config(apr_pool_t * p, server_rec * s)
+{
+ info_svr_conf *conf =
+ (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf));
+
+ conf->more_info = apr_array_make(p, 20, sizeof(info_entry));
+ return conf;
+}
+
+static void *merge_info_config(apr_pool_t * p, void *basev, void *overridesv)
+{
+ info_svr_conf *new =
+ (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf));
+ info_svr_conf *base = (info_svr_conf *) basev;
+ info_svr_conf *overrides = (info_svr_conf *) overridesv;
+
+ new->more_info =
+ apr_array_append(p, overrides->more_info, base->more_info);
+ return new;
+}
+
+static void put_int_flush_right(request_rec * r, int i, int field)
+{
+ if (field > 1 || i > 9)
+ put_int_flush_right(r, i / 10, field - 1);
+ if (i) {
+ if (r)
+ ap_rputc('0' + i % 10, r);
+ else
+ apr_file_putc((char)('0' + i % 10), out);
+ }
+ else {
+ if (r)
+ ap_rputs("&nbsp;", r);
+ else
+ apr_file_printf(out, " ");
+ }
+}
+
+static void set_fn_info(request_rec *r, const char *name)
+{
+ if (r)
+ ap_set_module_config(r->request_config, &info_module, (void *)name);
+ else
+ dump_config_fn_info = name;
+}
+
+static const char *get_fn_info(request_rec *r)
+{
+ if (r)
+ return ap_get_module_config(r->request_config, &info_module);
+ else
+ return dump_config_fn_info;
+}
+
+
+static void mod_info_indent(request_rec * r, int nest,
+ const char *thisfn, int linenum)
+{
+ int i;
+ const char *prevfn = get_fn_info(r);
+ if (thisfn == NULL)
+ thisfn = "*UNKNOWN*";
+ if (prevfn == NULL || 0 != strcmp(prevfn, thisfn)) {
+ if (r) {
+ thisfn = ap_escape_html(r->pool, thisfn);
+ ap_rprintf(r, "<dd><tt><strong>In file: %s</strong></tt></dd>\n",
+ thisfn);
+ }
+ else {
+ apr_file_printf(out, "# In file: %s\n", thisfn);
+ }
+ set_fn_info(r, thisfn);
+ }
+
+ if (r) {
+ ap_rputs("<dd><tt>", r);
+ put_int_flush_right(r, linenum > 0 ? linenum : 0, 4);
+ ap_rputs(":&nbsp;", r);
+ }
+ else if (linenum > 0) {
+ for (i = 1; i <= nest; ++i)
+ apr_file_printf(out, " ");
+ apr_file_putc('#', out);
+ put_int_flush_right(r, linenum, 4);
+ apr_file_printf(out, ":\n");
+ }
+
+ for (i = 1; i <= nest; ++i) {
+ if (r)
+ ap_rputs("&nbsp;&nbsp;", r);
+ else
+ apr_file_printf(out, " ");
+ }
+}
+
+static void mod_info_show_cmd(request_rec * r, const ap_directive_t * dir,
+ int nest)
+{
+ mod_info_indent(r, nest, dir->filename, dir->line_num);
+ if (r)
+ ap_rprintf(r, "%s <i>%s</i></tt></dd>\n",
+ ap_escape_html(r->pool, dir->directive),
+ ap_escape_html(r->pool, dir->args));
+ else
+ apr_file_printf(out, "%s %s\n", dir->directive, dir->args);
+}
+
+static void mod_info_show_open(request_rec * r, const ap_directive_t * dir,
+ int nest)
+{
+ mod_info_indent(r, nest, dir->filename, dir->line_num);
+ if (r)
+ ap_rprintf(r, "%s %s</tt></dd>\n",
+ ap_escape_html(r->pool, dir->directive),
+ ap_escape_html(r->pool, dir->args));
+ else
+ apr_file_printf(out, "%s %s\n", dir->directive, dir->args);
+}
+
+static void mod_info_show_close(request_rec * r, const ap_directive_t * dir,
+ int nest)
+{
+ const char *dirname = dir->directive;
+ mod_info_indent(r, nest, dir->filename, 0);
+ if (*dirname == '<') {
+ if (r)
+ ap_rprintf(r, "&lt;/%s&gt;</tt></dd>",
+ ap_escape_html(r->pool, dirname + 1));
+ else
+ apr_file_printf(out, "</%s>\n", dirname + 1);
+ }
+ else {
+ if (r)
+ ap_rprintf(r, "/%s</tt></dd>", ap_escape_html(r->pool, dirname));
+ else
+ apr_file_printf(out, "/%s\n", dirname);
+ }
+}
+
+static int mod_info_has_cmd(const command_rec * cmds, ap_directive_t * dir)
+{
+ const command_rec *cmd;
+ if (cmds == NULL)
+ return 1;
+ for (cmd = cmds; cmd->name; ++cmd) {
+ if (strcasecmp(cmd->name, dir->directive) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+static void mod_info_show_parents(request_rec * r, ap_directive_t * node,
+ int from, int to)
+{
+ if (from < to)
+ mod_info_show_parents(r, node->parent, from, to - 1);
+ mod_info_show_open(r, node, to);
+}
+
+static int mod_info_module_cmds(request_rec * r, const command_rec * cmds,
+ ap_directive_t * node, int from, int level)
+{
+ int shown = from;
+ ap_directive_t *dir;
+ if (level == 0)
+ set_fn_info(r, NULL);
+ for (dir = node; dir; dir = dir->next) {
+ if (dir->first_child != NULL) {
+ if (level < mod_info_module_cmds(r, cmds, dir->first_child,
+ shown, level + 1)) {
+ shown = level;
+ mod_info_show_close(r, dir, level);
+ }
+ }
+ else if (mod_info_has_cmd(cmds, dir)) {
+ if (shown < level) {
+ mod_info_show_parents(r, dir->parent, shown, level - 1);
+ shown = level;
+ }
+ mod_info_show_cmd(r, dir, level);
+ }
+ }
+ return shown;
+}
+
+typedef struct
+{ /*XXX: should get something from apr_hooks.h instead */
+ void (*pFunc) (void); /* just to get the right size */
+ const char *szName;
+ const char *const *aszPredecessors;
+ const char *const *aszSuccessors;
+ int nOrder;
+} hook_struct_t;
+
+/*
+ * hook_get_t is a pointer to a function that takes void as an argument and
+ * returns a pointer to an apr_array_header_t. The nasty WIN32 ifdef
+ * is required to account for the fact that the ap_hook* calls all use
+ * STDCALL calling convention.
+ */
+typedef apr_array_header_t *(
+#ifdef WIN32
+ __stdcall
+#endif
+ * hook_get_t) (void);
+
+typedef struct
+{
+ const char *name;
+ hook_get_t get;
+} hook_lookup_t;
+
+static hook_lookup_t startup_hooks[] = {
+ {"Pre-Config", ap_hook_get_pre_config},
+ {"Check Configuration", ap_hook_get_check_config},
+ {"Test Configuration", ap_hook_get_test_config},
+ {"Post Configuration", ap_hook_get_post_config},
+ {"Open Logs", ap_hook_get_open_logs},
+ {"Pre-MPM", ap_hook_get_pre_mpm},
+ {"MPM", ap_hook_get_mpm},
+ {"Drop Privileges", ap_hook_get_drop_privileges},
+ {"Retrieve Optional Functions", ap_hook_get_optional_fn_retrieve},
+ {"Child Init", ap_hook_get_child_init},
+ {NULL},
+};
+
+static hook_lookup_t request_hooks[] = {
+ {"Pre-Connection", ap_hook_get_pre_connection},
+ {"Create Connection", ap_hook_get_create_connection},
+ {"Process Connection", ap_hook_get_process_connection},
+ {"Create Request", ap_hook_get_create_request},
+ {"Pre-Read Request", ap_hook_get_pre_read_request},
+ {"Post-Read Request", ap_hook_get_post_read_request},
+ {"Header Parse", ap_hook_get_header_parser},
+ {"HTTP Scheme", ap_hook_get_http_scheme},
+ {"Default Port", ap_hook_get_default_port},
+ {"Quick Handler", ap_hook_get_quick_handler},
+ {"Translate Name", ap_hook_get_translate_name},
+ {"Map to Storage", ap_hook_get_map_to_storage},
+ {"Check Access", ap_hook_get_access_checker_ex},
+ {"Check Access (legacy)", ap_hook_get_access_checker},
+ {"Verify User ID", ap_hook_get_check_user_id},
+ {"Note Authentication Failure", ap_hook_get_note_auth_failure},
+ {"Verify User Access", ap_hook_get_auth_checker},
+ {"Check Type", ap_hook_get_type_checker},
+ {"Fixups", ap_hook_get_fixups},
+ {"Insert Filters", ap_hook_get_insert_filter},
+ {"Content Handlers", ap_hook_get_handler},
+ {"Transaction Logging", ap_hook_get_log_transaction},
+ {"Insert Errors", ap_hook_get_insert_error_filter},
+ {"Generate Log ID", ap_hook_get_generate_log_id},
+ {NULL},
+};
+
+static hook_lookup_t other_hooks[] = {
+ {"Monitor", ap_hook_get_monitor},
+ {"Child Status", ap_hook_get_child_status},
+ {"End Generation", ap_hook_get_end_generation},
+ {"Error Logging", ap_hook_get_error_log},
+ {"Query MPM Attributes", ap_hook_get_mpm_query},
+ {"Query MPM Name", ap_hook_get_mpm_get_name},
+ {"Register Timed Callback", ap_hook_get_mpm_register_timed_callback},
+ {"Extend Expression Parser", ap_hook_get_expr_lookup},
+ {"Set Management Items", ap_hook_get_get_mgmt_items},
+#if AP_ENABLE_EXCEPTION_HOOK
+ {"Handle Fatal Exceptions", ap_hook_get_fatal_exception},
+#endif
+ {NULL},
+};
+
+static int module_find_hook(module * modp, hook_get_t hook_get)
+{
+ int i;
+ apr_array_header_t *hooks = hook_get();
+ hook_struct_t *elts;
+
+ if (!hooks) {
+ return 0;
+ }
+
+ elts = (hook_struct_t *) hooks->elts;
+
+ for (i = 0; i < hooks->nelts; i++) {
+ if (strcmp(elts[i].szName, modp->name) == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void module_participate(request_rec * r,
+ module * modp,
+ hook_lookup_t * lookup, int *comma)
+{
+ if (module_find_hook(modp, lookup->get)) {
+ if (*comma) {
+ ap_rputs(", ", r);
+ }
+ ap_rvputs(r, "<tt>", lookup->name, "</tt>", NULL);
+ *comma = 1;
+ }
+}
+
+static void module_request_hook_participate(request_rec * r, module * modp)
+{
+ int i, comma = 0;
+
+ ap_rputs("<dt><strong>Request Phase Participation:</strong>\n", r);
+
+ for (i = 0; request_hooks[i].name; i++) {
+ module_participate(r, modp, &request_hooks[i], &comma);
+ }
+
+ if (!comma) {
+ ap_rputs("<tt> <em>none</em></tt>", r);
+ }
+ ap_rputs("</dt>\n", r);
+}
+
+static const char *find_more_info(server_rec * s, const char *module_name)
+{
+ int i;
+ info_svr_conf *conf =
+ (info_svr_conf *) ap_get_module_config(s->module_config,
+ &info_module);
+ info_entry *entry = (info_entry *) conf->more_info->elts;
+
+ if (!module_name) {
+ return 0;
+ }
+ for (i = 0; i < conf->more_info->nelts; i++) {
+ if (!strcmp(module_name, entry->name)) {
+ return entry->info;
+ }
+ entry++;
+ }
+ return 0;
+}
+
+static int show_server_settings(request_rec * r)
+{
+ server_rec *serv = r->server;
+ int max_daemons, forked, threaded;
+
+ ap_rputs("<h2><a name=\"server\">Server Settings</a></h2>", r);
+ ap_rprintf(r,
+ "<dl><dt><strong>Server Version:</strong> "
+ "<font size=\"+1\"><tt>%s</tt></font></dt>\n",
+ ap_get_server_description());
+ ap_rprintf(r,
+ "<dt><strong>Server Built:</strong> "
+ "<font size=\"+1\"><tt>%s</tt></font></dt>\n",
+ ap_get_server_built());
+ ap_rprintf(r,
+ "<dt><strong>Server loaded APR Version:</strong> "
+ "<tt>%s</tt></dt>\n", apr_version_string());
+ ap_rprintf(r,
+ "<dt><strong>Compiled with APR Version:</strong> "
+ "<tt>%s</tt></dt>\n", APR_VERSION_STRING);
+#if APR_MAJOR_VERSION < 2
+ ap_rprintf(r,
+ "<dt><strong>Server loaded APU Version:</strong> "
+ "<tt>%s</tt></dt>\n", apu_version_string());
+ ap_rprintf(r,
+ "<dt><strong>Compiled with APU Version:</strong> "
+ "<tt>%s</tt></dt>\n", APU_VERSION_STRING);
+#endif
+ ap_rprintf(r,
+ "<dt><strong>Module Magic Number:</strong> "
+ "<tt>%d:%d</tt></dt>\n", MODULE_MAGIC_NUMBER_MAJOR,
+ MODULE_MAGIC_NUMBER_MINOR);
+ ap_rprintf(r,
+ "<dt><strong>Hostname/port:</strong> "
+ "<tt>%s:%u</tt></dt>\n",
+ ap_escape_html(r->pool, ap_get_server_name(r)),
+ ap_get_server_port(r));
+ ap_rprintf(r,
+ "<dt><strong>Timeouts:</strong> "
+ "<tt>connection: %d &nbsp;&nbsp; "
+ "keep-alive: %d</tt></dt>",
+ (int) (apr_time_sec(serv->timeout)),
+ (int) (apr_time_sec(serv->keep_alive_timeout)));
+ ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);
+ ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded);
+ ap_mpm_query(AP_MPMQ_IS_FORKED, &forked);
+ ap_rprintf(r, "<dt><strong>MPM Name:</strong> <tt>%s</tt></dt>\n",
+ ap_show_mpm());
+ ap_rprintf(r,
+ "<dt><strong>MPM Information:</strong> "
+ "<tt>Max Daemons: %d Threaded: %s Forked: %s</tt></dt>\n",
+ max_daemons, threaded ? "yes" : "no", forked ? "yes" : "no");
+ ap_rprintf(r,
+ "<dt><strong>Server Architecture:</strong> "
+ "<tt>%ld-bit</tt></dt>\n", 8 * (long) sizeof(void *));
+ ap_rprintf(r,
+ "<dt><strong>Server Root:</strong> "
+ "<tt>%s</tt></dt>\n", ap_server_root);
+ ap_rprintf(r,
+ "<dt><strong>Config File:</strong> "
+ "<tt>%s</tt></dt>\n", ap_conftree->filename);
+
+ ap_rputs("<dt><strong>Server Built With:</strong>\n"
+ "<tt style=\"white-space: pre;\">\n", r);
+
+ /* TODO: Not all of these defines are getting set like they do in main.c.
+ * Missing some headers?
+ */
+
+#ifdef BIG_SECURITY_HOLE
+ ap_rputs(" -D BIG_SECURITY_HOLE\n", r);
+#endif
+
+#ifdef SECURITY_HOLE_PASS_AUTHORIZATION
+ ap_rputs(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n", r);
+#endif
+
+#ifdef OS
+ ap_rputs(" -D OS=\"" OS "\"\n", r);
+#endif
+
+#ifdef HAVE_SHMGET
+ ap_rputs(" -D HAVE_SHMGET\n", r);
+#endif
+
+#if APR_FILE_BASED_SHM
+ ap_rputs(" -D APR_FILE_BASED_SHM\n", r);
+#endif
+
+#if APR_HAS_SENDFILE
+ ap_rputs(" -D APR_HAS_SENDFILE\n", r);
+#endif
+
+#if APR_HAS_MMAP
+ ap_rputs(" -D APR_HAS_MMAP\n", r);
+#endif
+
+#ifdef NO_WRITEV
+ ap_rputs(" -D NO_WRITEV\n", r);
+#endif
+
+#ifdef NO_LINGCLOSE
+ ap_rputs(" -D NO_LINGCLOSE\n", r);
+#endif
+
+#if APR_HAVE_IPV6
+ ap_rputs(" -D APR_HAVE_IPV6 (IPv4-mapped addresses ", r);
+#ifdef AP_ENABLE_V4_MAPPED
+ ap_rputs("enabled)\n", r);
+#else
+ ap_rputs("disabled)\n", r);
+#endif
+#endif
+
+#if APR_USE_FLOCK_SERIALIZE
+ ap_rputs(" -D APR_USE_FLOCK_SERIALIZE\n", r);
+#endif
+
+#if APR_USE_SYSVSEM_SERIALIZE
+ ap_rputs(" -D APR_USE_SYSVSEM_SERIALIZE\n", r);
+#endif
+
+#if APR_USE_POSIXSEM_SERIALIZE
+ ap_rputs(" -D APR_USE_POSIXSEM_SERIALIZE\n", r);
+#endif
+
+#if APR_USE_FCNTL_SERIALIZE
+ ap_rputs(" -D APR_USE_FCNTL_SERIALIZE\n", r);
+#endif
+
+#if APR_USE_PROC_PTHREAD_SERIALIZE
+ ap_rputs(" -D APR_USE_PROC_PTHREAD_SERIALIZE\n", r);
+#endif
+#if APR_PROCESS_LOCK_IS_GLOBAL
+ ap_rputs(" -D APR_PROCESS_LOCK_IS_GLOBAL\n", r);
+#endif
+
+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+ ap_rputs(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n", r);
+#endif
+
+#if APR_HAS_OTHER_CHILD
+ ap_rputs(" -D APR_HAS_OTHER_CHILD\n", r);
+#endif
+
+#ifdef AP_HAVE_RELIABLE_PIPED_LOGS
+ ap_rputs(" -D AP_HAVE_RELIABLE_PIPED_LOGS\n", r);
+#endif
+
+#ifdef BUFFERED_LOGS
+ ap_rputs(" -D BUFFERED_LOGS\n", r);
+#ifdef PIPE_BUF
+ ap_rputs(" -D PIPE_BUF=%ld\n", (long) PIPE_BUF, r);
+#endif
+#endif
+
+#if APR_CHARSET_EBCDIC
+ ap_rputs(" -D APR_CHARSET_EBCDIC\n", r);
+#endif
+
+#ifdef NEED_HASHBANG_EMUL
+ ap_rputs(" -D NEED_HASHBANG_EMUL\n", r);
+#endif
+
+/* This list displays the compiled in default paths: */
+#ifdef HTTPD_ROOT
+ ap_rputs(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n", r);
+#endif
+
+#ifdef SUEXEC_BIN
+ ap_rputs(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n", r);
+#endif
+
+#ifdef DEFAULT_PIDLOG
+ ap_rputs(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n", r);
+#endif
+
+#ifdef DEFAULT_SCOREBOARD
+ ap_rputs(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n", r);
+#endif
+
+#ifdef DEFAULT_ERRORLOG
+ ap_rputs(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n", r);
+#endif
+
+
+#ifdef AP_TYPES_CONFIG_FILE
+ ap_rputs(" -D AP_TYPES_CONFIG_FILE=\"" AP_TYPES_CONFIG_FILE "\"\n", r);
+#endif
+
+#ifdef SERVER_CONFIG_FILE
+ ap_rputs(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n", r);
+#endif
+ ap_rputs("</tt></dt>\n", r);
+ ap_rputs("</dl><hr />", r);
+ return 0;
+}
+
+static int dump_a_hook(request_rec * r, hook_get_t hook_get)
+{
+ int i;
+ char qs;
+ hook_struct_t *elts;
+ apr_array_header_t *hooks = hook_get();
+
+ if (!hooks) {
+ return 0;
+ }
+
+ if (r->args && strcasecmp(r->args, "hooks") == 0) {
+ qs = '?';
+ }
+ else {
+ qs = '#';
+ }
+
+ elts = (hook_struct_t *) hooks->elts;
+
+ for (i = 0; i < hooks->nelts; i++) {
+ ap_rprintf(r,
+ "&nbsp;&nbsp; %02d <a href=\"%c%s\">%s</a> <br/>",
+ elts[i].nOrder, qs, elts[i].szName, elts[i].szName);
+ }
+ return 0;
+}
+
+static int show_active_hooks(request_rec * r)
+{
+ int i;
+ ap_rputs("<h2><a name=\"startup_hooks\">Startup Hooks</a></h2>\n<dl>", r);
+
+ for (i = 0; startup_hooks[i].name; i++) {
+ ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n",
+ startup_hooks[i].name);
+ dump_a_hook(r, startup_hooks[i].get);
+ ap_rputs("\n </tt>\n</dt>\n", r);
+ }
+
+ ap_rputs
+ ("</dl>\n<hr />\n<h2><a name=\"request_hooks\">Request Hooks</a></h2>\n<dl>",
+ r);
+
+ for (i = 0; request_hooks[i].name; i++) {
+ ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n",
+ request_hooks[i].name);
+ dump_a_hook(r, request_hooks[i].get);
+ ap_rputs("\n </tt>\n</dt>\n", r);
+ }
+
+ ap_rputs
+ ("</dl>\n<hr />\n<h2><a name=\"other_hooks\">Other Hooks</a></h2>\n<dl>",
+ r);
+
+ for (i = 0; other_hooks[i].name; i++) {
+ ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n",
+ other_hooks[i].name);
+ dump_a_hook(r, other_hooks[i].get);
+ ap_rputs("\n </tt>\n</dt>\n", r);
+ }
+
+ ap_rputs("</dl>\n<hr />\n", r);
+
+ return 0;
+}
+
+static int cmp_provider_groups(const void *a_, const void *b_)
+{
+ const ap_list_provider_groups_t *a = a_, *b = b_;
+ int ret = strcmp(a->provider_group, b->provider_group);
+ if (!ret)
+ ret = strcmp(a->provider_version, b->provider_version);
+ return ret;
+}
+
+static int cmp_provider_names(const void *a_, const void *b_)
+{
+ const ap_list_provider_names_t *a = a_, *b = b_;
+ return strcmp(a->provider_name, b->provider_name);
+}
+
+static void show_providers(request_rec *r)
+{
+ apr_array_header_t *groups = ap_list_provider_groups(r->pool);
+ ap_list_provider_groups_t *group;
+ apr_array_header_t *names;
+ ap_list_provider_names_t *name;
+ int i,j;
+ const char *cur_group = NULL;
+
+ qsort(groups->elts, groups->nelts, sizeof(ap_list_provider_groups_t),
+ cmp_provider_groups);
+ ap_rputs("<h2><a name=\"providers\">Providers</a></h2>\n<dl>", r);
+
+ for (i = 0; i < groups->nelts; i++) {
+ group = &APR_ARRAY_IDX(groups, i, ap_list_provider_groups_t);
+ if (!cur_group || strcmp(cur_group, group->provider_group) != 0) {
+ if (cur_group)
+ ap_rputs("\n</dt>\n", r);
+ cur_group = group->provider_group;
+ ap_rprintf(r, "<dt><strong>%s</strong> (version <tt>%s</tt>):"
+ "\n <br />\n", cur_group, group->provider_version);
+ }
+ names = ap_list_provider_names(r->pool, group->provider_group,
+ group->provider_version);
+ qsort(names->elts, names->nelts, sizeof(ap_list_provider_names_t),
+ cmp_provider_names);
+ for (j = 0; j < names->nelts; j++) {
+ name = &APR_ARRAY_IDX(names, j, ap_list_provider_names_t);
+ ap_rprintf(r, "<tt>&nbsp;&nbsp;%s</tt><br/>", name->provider_name);
+ }
+ }
+ if (cur_group)
+ ap_rputs("\n</dt>\n", r);
+ ap_rputs("</dl>\n<hr />\n", r);
+}
+
+static int cmp_module_name(const void *a_, const void *b_)
+{
+ const module * const *a = a_;
+ const module * const *b = b_;
+ return strcmp((*a)->name, (*b)->name);
+}
+
+static apr_array_header_t *get_sorted_modules(apr_pool_t *p)
+{
+ apr_array_header_t *arr = apr_array_make(p, 64, sizeof(module *));
+ module *modp, **entry;
+ for (modp = ap_top_module; modp; modp = modp->next) {
+ entry = &APR_ARRAY_PUSH(arr, module *);
+ *entry = modp;
+ }
+ qsort(arr->elts, arr->nelts, sizeof(module *), cmp_module_name);
+ return arr;
+}
+
+static int display_info(request_rec * r)
+{
+ module *modp = NULL;
+ const char *more_info;
+ const command_rec *cmd;
+ apr_array_header_t *modules = NULL;
+ int i;
+
+ if (strcmp(r->handler, "server-info")) {
+ return DECLINED;
+ }
+
+ r->allowed |= (AP_METHOD_BIT << M_GET);
+ if (r->method_number != M_GET) {
+ return DECLINED;
+ }
+
+ ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+
+ ap_rputs(DOCTYPE_XHTML_1_0T
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
+ "<head>\n"
+ " <title>Server Information</title>\n" "</head>\n", r);
+ ap_rputs("<body><h1 style=\"text-align: center\">"
+ "Apache Server Information</h1>\n", r);
+ if (!r->args || strcasecmp(r->args, "list")) {
+ if (!r->args) {
+ ap_rputs("<dl><dt><tt>Subpages:<br />", r);
+ ap_rputs("<a href=\"?config\">Configuration Files</a>, "
+ "<a href=\"?server\">Server Settings</a>, "
+ "<a href=\"?list\">Module List</a>, "
+ "<a href=\"?hooks\">Active Hooks</a>, "
+ "<a href=\"?providers\">Available Providers</a>", r);
+ ap_rputs("</tt></dt></dl><hr />", r);
+
+ ap_rputs("<dl><dt><tt>Sections:<br />", r);
+ ap_rputs("<a href=\"#modules\">Loaded Modules</a>, "
+ "<a href=\"#server\">Server Settings</a>, "
+ "<a href=\"#startup_hooks\">Startup Hooks</a>, "
+ "<a href=\"#request_hooks\">Request Hooks</a>, "
+ "<a href=\"#other_hooks\">Other Hooks</a>, "
+ "<a href=\"#providers\">Providers</a>", r);
+ ap_rputs("</tt></dt></dl><hr />", r);
+
+ ap_rputs("<h2><a name=\"modules\">Loaded Modules</a></h2>"
+ "<dl><dt><tt>", r);
+
+ modules = get_sorted_modules(r->pool);
+ for (i = 0; i < modules->nelts; i++) {
+ modp = APR_ARRAY_IDX(modules, i, module *);
+ ap_rprintf(r, "<a href=\"#%s\">%s</a>", modp->name,
+ modp->name);
+ if (i < modules->nelts) {
+ ap_rputs(", ", r);
+ }
+ }
+ ap_rputs("</tt></dt></dl><hr />", r);
+ }
+
+ if (!r->args || !strcasecmp(r->args, "server")) {
+ show_server_settings(r);
+ }
+
+ if (!r->args || !strcasecmp(r->args, "hooks")) {
+ show_active_hooks(r);
+ }
+
+ if (!r->args || !strcasecmp(r->args, "providers")) {
+ show_providers(r);
+ }
+
+ if (r->args && 0 == strcasecmp(r->args, "config")) {
+ ap_rputs("<dl><dt><strong>Configuration:</strong>\n", r);
+ mod_info_module_cmds(r, NULL, ap_conftree, 0, 0);
+ ap_rputs("</dl><hr />", r);
+ }
+ else {
+ int comma = 0;
+ if (!modules)
+ modules = get_sorted_modules(r->pool);
+ for (i = 0; i < modules->nelts; i++) {
+ modp = APR_ARRAY_IDX(modules, i, module *);
+ if (!r->args || !strcasecmp(modp->name, r->args)) {
+ ap_rprintf(r,
+ "<dl><dt><a name=\"%s\"><strong>Module Name:</strong></a> "
+ "<font size=\"+1\"><tt><a href=\"?%s\">%s</a></tt></font></dt>\n",
+ modp->name, modp->name, modp->name);
+ ap_rputs("<dt><strong>Content handlers:</strong> ", r);
+
+ if (module_find_hook(modp, ap_hook_get_handler)) {
+ ap_rputs("<tt> <em>yes</em></tt>", r);
+ }
+ else {
+ ap_rputs("<tt> <em>none</em></tt>", r);
+ }
+
+ ap_rputs("</dt>", r);
+ ap_rputs
+ ("<dt><strong>Configuration Phase Participation:</strong>\n",
+ r);
+ if (modp->create_dir_config) {
+ if (comma) {
+ ap_rputs(", ", r);
+ }
+ ap_rputs("<tt>Create Directory Config</tt>", r);
+ comma = 1;
+ }
+ if (modp->merge_dir_config) {
+ if (comma) {
+ ap_rputs(", ", r);
+ }
+ ap_rputs("<tt>Merge Directory Configs</tt>", r);
+ comma = 1;
+ }
+ if (modp->create_server_config) {
+ if (comma) {
+ ap_rputs(", ", r);
+ }
+ ap_rputs("<tt>Create Server Config</tt>", r);
+ comma = 1;
+ }
+ if (modp->merge_server_config) {
+ if (comma) {
+ ap_rputs(", ", r);
+ }
+ ap_rputs("<tt>Merge Server Configs</tt>", r);
+ comma = 1;
+ }
+ if (!comma)
+ ap_rputs("<tt> <em>none</em></tt>", r);
+ comma = 0;
+ ap_rputs("</dt>", r);
+
+ module_request_hook_participate(r, modp);
+
+ cmd = modp->cmds;
+ if (cmd) {
+ ap_rputs
+ ("<dt><strong>Module Directives:</strong></dt>",
+ r);
+ while (cmd) {
+ if (cmd->name) {
+ ap_rprintf(r, "<dd><tt>%s%s - <i>",
+ ap_escape_html(r->pool, cmd->name),
+ cmd->name[0] == '<' ? "&gt;" : "");
+ if (cmd->errmsg) {
+ ap_rputs(ap_escape_html(r->pool, cmd->errmsg), r);
+ }
+ ap_rputs("</i></tt></dd>\n", r);
+ }
+ else {
+ break;
+ }
+ cmd++;
+ }
+ ap_rputs
+ ("<dt><strong>Current Configuration:</strong></dt>\n",
+ r);
+ mod_info_module_cmds(r, modp->cmds, ap_conftree, 0,
+ 0);
+ }
+ else {
+ ap_rputs
+ ("<dt><strong>Module Directives:</strong> <tt>none</tt></dt>",
+ r);
+ }
+ more_info = find_more_info(r->server, modp->name);
+ if (more_info) {
+ ap_rputs
+ ("<dt><strong>Additional Information:</strong>\n</dt><dd>",
+ r);
+ ap_rputs(more_info, r);
+ ap_rputs("</dd>", r);
+ }
+ ap_rputs("</dl><hr />\n", r);
+ if (r->args) {
+ break;
+ }
+ }
+ }
+ if (!modp && r->args && strcasecmp(r->args, "server")) {
+ ap_rputs("<p><b>No such module</b></p>\n", r);
+ }
+ }
+ }
+ else {
+ ap_rputs("<dl><dt>Server Module List</dt>", r);
+ modules = get_sorted_modules(r->pool);
+ for (i = 0; i < modules->nelts; i++) {
+ modp = APR_ARRAY_IDX(modules, i, module *);
+ ap_rputs("<dd>", r);
+ ap_rputs(modp->name, r);
+ ap_rputs("</dd>", r);
+ }
+ ap_rputs("</dl><hr />", r);
+ }
+ ap_rputs(ap_psignature("", r), r);
+ ap_rputs("</body></html>\n", r);
+ /* Done, turn off timeout, close file and return */
+ return 0;
+}
+
+static const char *add_module_info(cmd_parms * cmd, void *dummy,
+ const char *name, const char *info)
+{
+ server_rec *s = cmd->server;
+ info_svr_conf *conf =
+ (info_svr_conf *) ap_get_module_config(s->module_config,
+ &info_module);
+ info_entry *new = apr_array_push(conf->more_info);
+
+ new->name = name;
+ new->info = info;
+ return NULL;
+}
+
+static const command_rec info_cmds[] = {
+ AP_INIT_TAKE2("AddModuleInfo", add_module_info, NULL, RSRC_CONF,
+ "a module name and additional information on that module"),
+ {NULL}
+};
+
+static int check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp,
+ server_rec *s)
+{
+ if (ap_exists_config_define("DUMP_CONFIG")) {
+ apr_file_open_stdout(&out, ptemp);
+ mod_info_module_cmds(NULL, NULL, ap_conftree, 0, 0);
+ }
+
+ return DECLINED;
+}
+
+
+static void register_hooks(apr_pool_t * p)
+{
+ ap_hook_handler(display_info, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_check_config(check_config, NULL, NULL, APR_HOOK_FIRST);
+}
+
+AP_DECLARE_MODULE(info) = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ create_info_config, /* server config */
+ merge_info_config, /* merge server config */
+ info_cmds, /* command apr_table_t */
+ register_hooks
+};
diff --git a/modules/generators/mod_info.dep b/modules/generators/mod_info.dep
new file mode 100644
index 0000000..cdfc02b
--- /dev/null
+++ b/modules/generators/mod_info.dep
@@ -0,0 +1,66 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_info.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_info.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_mpm.h"\
+ "..\..\include\ap_provider.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_connection.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\mpm_common.h"\
+ "..\..\include\os.h"\
+ "..\..\include\scoreboard.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\include\util_script.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.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-util\include\apu.h"\
+ "..\..\srclib\apr-util\include\apu_version.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_hash.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_lib.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_version.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+
diff --git a/modules/generators/mod_info.dsp b/modules/generators/mod_info.dsp
new file mode 100644
index 0000000..524ebf8
--- /dev/null
+++ b/modules/generators/mod_info.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_info" - 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_info - 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_info.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_info.mak" CFG="mod_info - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_info - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_info - 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_info - 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_info_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_info.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_info.so" /d LONG_NAME="info_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_info.so" /base:@..\..\os\win32\BaseAddr.ref,mod_info.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_info.so" /base:@..\..\os\win32\BaseAddr.ref,mod_info.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_info.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_info - 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_info_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_info.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_info.so" /d LONG_NAME="info_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_info.so" /base:@..\..\os\win32\BaseAddr.ref,mod_info.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_info.so" /base:@..\..\os\win32\BaseAddr.ref,mod_info.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_info.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_info - Win32 Release"
+# Name "mod_info - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_info.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/generators/mod_info.exp b/modules/generators/mod_info.exp
new file mode 100644
index 0000000..c304fa7
--- /dev/null
+++ b/modules/generators/mod_info.exp
@@ -0,0 +1 @@
+info_module
diff --git a/modules/generators/mod_info.mak b/modules/generators/mod_info.mak
new file mode 100644
index 0000000..b0de8a1
--- /dev/null
+++ b/modules/generators/mod_info.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_info.dsp
+!IF "$(CFG)" == ""
+CFG=mod_info - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_info - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_info - Win32 Release" && "$(CFG)" != "mod_info - 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_info.mak" CFG="mod_info - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_info - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_info - 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_info - 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_info.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_info.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_info.obj"
+ -@erase "$(INTDIR)\mod_info.res"
+ -@erase "$(INTDIR)\mod_info_src.idb"
+ -@erase "$(INTDIR)\mod_info_src.pdb"
+ -@erase "$(OUTDIR)\mod_info.exp"
+ -@erase "$(OUTDIR)\mod_info.lib"
+ -@erase "$(OUTDIR)\mod_info.pdb"
+ -@erase "$(OUTDIR)\mod_info.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_info_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_info.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_info.so" /d LONG_NAME="info_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_info.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_info.pdb" /debug /out:"$(OUTDIR)\mod_info.so" /implib:"$(OUTDIR)\mod_info.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_info.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_info.obj" \
+ "$(INTDIR)\mod_info.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_info.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_info.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_info.so"
+ if exist .\Release\mod_info.so.manifest mt.exe -manifest .\Release\mod_info.so.manifest -outputresource:.\Release\mod_info.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_info - 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_info.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_info.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_info.obj"
+ -@erase "$(INTDIR)\mod_info.res"
+ -@erase "$(INTDIR)\mod_info_src.idb"
+ -@erase "$(INTDIR)\mod_info_src.pdb"
+ -@erase "$(OUTDIR)\mod_info.exp"
+ -@erase "$(OUTDIR)\mod_info.lib"
+ -@erase "$(OUTDIR)\mod_info.pdb"
+ -@erase "$(OUTDIR)\mod_info.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_info_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_info.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_info.so" /d LONG_NAME="info_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_info.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_info.pdb" /debug /out:"$(OUTDIR)\mod_info.so" /implib:"$(OUTDIR)\mod_info.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_info.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_info.obj" \
+ "$(INTDIR)\mod_info.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_info.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_info.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_info.so"
+ if exist .\Debug\mod_info.so.manifest mt.exe -manifest .\Debug\mod_info.so.manifest -outputresource:.\Debug\mod_info.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_info.dep")
+!INCLUDE "mod_info.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_info.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_info - Win32 Release" || "$(CFG)" == "mod_info - Win32 Debug"
+
+!IF "$(CFG)" == "mod_info - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_info - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_info - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_info - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_info - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_info - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_info - Win32 Release"
+
+
+"$(INTDIR)\mod_info.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_info.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_info.so" /d LONG_NAME="info_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_info - Win32 Debug"
+
+
+"$(INTDIR)\mod_info.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_info.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_info.so" /d LONG_NAME="info_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_info.c
+
+"$(INTDIR)\mod_info.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
new file mode 100644
index 0000000..5917953
--- /dev/null
+++ b/modules/generators/mod_status.c
@@ -0,0 +1,1051 @@
+/* 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.
+ */
+
+/* Status Module. Display lots of internal data about how Apache is
+ * performing and the state of all children processes.
+ *
+ * To enable this, add the following lines into any config file:
+ *
+ * <Location /server-status>
+ * SetHandler server-status
+ * </Location>
+ *
+ * You may want to protect this location by password or domain so no one
+ * else can look at it. Then you can access the statistics with a URL like:
+ *
+ * http://your_server_name/server-status
+ *
+ * /server-status - Returns page using tables
+ * /server-status?notable - Returns page for browsers without table support
+ * /server-status?refresh - Returns page with 1 second refresh
+ * /server-status?refresh=6 - Returns page with refresh every 6 seconds
+ * /server-status?auto - Returns page with data for automatic parsing
+ *
+ * Mark Cox, mark@ukweb.com, November 1995
+ *
+ * 12.11.95 Initial version for www.telescope.org
+ * 13.3.96 Updated to remove rprintf's [Mark]
+ * 18.3.96 Added CPU usage, process information, and tidied [Ben Laurie]
+ * 18.3.96 Make extra Scoreboard variables #definable
+ * 25.3.96 Make short report have full precision [Ben Laurie suggested]
+ * 25.3.96 Show uptime better [Mark/Ben Laurie]
+ * 29.3.96 Better HTML and explanation [Mark/Rob Hartill suggested]
+ * 09.4.96 Added message for non-STATUS compiled version
+ * 18.4.96 Added per child and per slot counters [Jim Jagielski]
+ * 01.5.96 Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
+ * 18.5.96 Adapted to use new rprintf() routine, incidentally fixing a missing
+ * piece in short reports [Ben Laurie]
+ * 21.5.96 Additional Status codes (DNS and LOGGING only enabled if
+ * extended STATUS is enabled) [George Burgyan/Jim J.]
+ * 10.8.98 Allow for extended status info at runtime (no more STATUS)
+ * [Jim J.]
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "ap_mpm.h"
+#include "util_script.h"
+#include <time.h>
+#include "scoreboard.h"
+#include "http_log.h"
+#include "mod_status.h"
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr_strings.h"
+
+#define STATUS_MAXLINE 64
+
+#define KBYTE 1024
+#define MBYTE 1048576L
+#define GBYTE 1073741824L
+
+#ifndef DEFAULT_TIME_FORMAT
+#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
+#endif
+
+#define STATUS_MAGIC_TYPE "application/x-httpd-status"
+
+module AP_MODULE_DECLARE_DATA status_module;
+
+static int server_limit, thread_limit, threads_per_child, max_servers,
+ is_async;
+
+/* Implement 'ap_run_status_hook'. */
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
+ (request_rec *r, int flags),
+ (r, flags),
+ OK, DECLINED)
+
+#ifdef HAVE_TIMES
+/* ugh... need to know if we're running with a pthread implementation
+ * such as linuxthreads that treats individual threads as distinct
+ * processes; that affects how we add up CPU time in a process
+ */
+static pid_t child_pid;
+#endif
+
+/* Format the number of bytes nicely */
+static void format_byte_out(request_rec *r, apr_off_t bytes)
+{
+ if (bytes < (5 * KBYTE))
+ ap_rprintf(r, "%d B", (int) bytes);
+ else if (bytes < (MBYTE / 2))
+ ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
+ else if (bytes < (GBYTE / 2))
+ ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
+ else
+ ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
+}
+
+static void format_kbyte_out(request_rec *r, apr_off_t kbytes)
+{
+ if (kbytes < KBYTE)
+ ap_rprintf(r, "%d kB", (int) kbytes);
+ else if (kbytes < MBYTE)
+ ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE);
+ else
+ ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE);
+}
+
+static void show_time(request_rec *r, apr_uint32_t tsecs)
+{
+ int days, hrs, mins, secs;
+
+ secs = (int)(tsecs % 60);
+ tsecs /= 60;
+ mins = (int)(tsecs % 60);
+ tsecs /= 60;
+ hrs = (int)(tsecs % 24);
+ days = (int)(tsecs / 24);
+
+ if (days)
+ ap_rprintf(r, " %d day%s", days, days == 1 ? "" : "s");
+
+ if (hrs)
+ ap_rprintf(r, " %d hour%s", hrs, hrs == 1 ? "" : "s");
+
+ if (mins)
+ ap_rprintf(r, " %d minute%s", mins, mins == 1 ? "" : "s");
+
+ if (secs)
+ ap_rprintf(r, " %d second%s", secs, secs == 1 ? "" : "s");
+}
+
+/* Main handler for x-httpd-status requests */
+
+/* ID values for command table */
+
+#define STAT_OPT_END -1
+#define STAT_OPT_REFRESH 0
+#define STAT_OPT_NOTABLE 1
+#define STAT_OPT_AUTO 2
+
+struct stat_opt {
+ int id;
+ const char *form_data_str;
+ const char *hdr_out_str;
+};
+
+static const struct stat_opt status_options[] = /* see #defines above */
+{
+ {STAT_OPT_REFRESH, "refresh", "Refresh"},
+ {STAT_OPT_NOTABLE, "notable", NULL},
+ {STAT_OPT_AUTO, "auto", NULL},
+ {STAT_OPT_END, NULL, NULL}
+};
+
+/* add another state for slots above the MaxRequestWorkers setting */
+#define SERVER_DISABLED SERVER_NUM_STATUS
+#define MOD_STATUS_NUM_STATUS (SERVER_NUM_STATUS+1)
+
+static char status_flags[MOD_STATUS_NUM_STATUS];
+
+static int status_handler(request_rec *r)
+{
+ const char *loc;
+ apr_time_t nowtime;
+ apr_uint32_t up_time;
+ ap_loadavg_t t;
+ int j, i, res, written;
+ int ready;
+ int busy;
+ unsigned long count;
+ unsigned long lres, my_lres, conn_lres;
+ apr_off_t bytes, my_bytes, conn_bytes;
+ apr_off_t bcount, kbcount;
+ long req_time;
+ apr_time_t duration_global;
+ apr_time_t duration_slot;
+ int short_report;
+ int no_table_report;
+ global_score *global_record;
+ worker_score *ws_record;
+ process_score *ps_record;
+ char *stat_buffer;
+ pid_t *pid_buffer, worker_pid;
+ int *thread_idle_buffer = NULL;
+ int *thread_busy_buffer = NULL;
+ clock_t tu, ts, tcu, tcs;
+ clock_t gu, gs, gcu, gcs;
+ ap_generation_t mpm_generation, worker_generation;
+#ifdef HAVE_TIMES
+ float tick;
+ int times_per_thread;
+#endif
+
+ if (strcmp(r->handler, STATUS_MAGIC_TYPE) && strcmp(r->handler,
+ "server-status")) {
+ return DECLINED;
+ }
+
+#ifdef HAVE_TIMES
+ times_per_thread = getpid() != child_pid;
+#endif
+
+ ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
+
+#ifdef HAVE_TIMES
+#ifdef _SC_CLK_TCK
+ tick = sysconf(_SC_CLK_TCK);
+#else
+ tick = HZ;
+#endif
+#endif
+
+ ready = 0;
+ busy = 0;
+ count = 0;
+ bcount = 0;
+ kbcount = 0;
+ duration_global = 0;
+ short_report = 0;
+ no_table_report = 0;
+
+ if (!ap_exists_scoreboard_image()) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01237)
+ "Server status unavailable in inetd mode");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
+ stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
+ if (is_async) {
+ thread_idle_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
+ thread_busy_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
+ }
+
+ nowtime = apr_time_now();
+#ifdef HAVE_TIMES
+ global_record = ap_get_scoreboard_global();
+ gu = global_record->times.tms_utime;
+ gs = global_record->times.tms_stime;
+ gcu = global_record->times.tms_cutime;
+ gcs = global_record->times.tms_cstime;
+#else
+ gu = gs = gcu = gcs = 0;
+#endif
+ tu = ts = tcu = tcs = 0;
+
+ r->allowed = (AP_METHOD_BIT << M_GET);
+ if (r->method_number != M_GET)
+ return DECLINED;
+
+ ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+
+ /*
+ * Simple table-driven form data set parser that lets you alter the header
+ */
+
+ if (r->args) {
+ i = 0;
+ while (status_options[i].id != STAT_OPT_END) {
+ if ((loc = ap_strstr_c(r->args,
+ status_options[i].form_data_str)) != NULL) {
+ switch (status_options[i].id) {
+ case STAT_OPT_REFRESH: {
+ apr_size_t len = strlen(status_options[i].form_data_str);
+ long t = 0;
+
+ if (*(loc + len ) == '=') {
+ t = atol(loc + len + 1);
+ }
+ apr_table_setn(r->headers_out,
+ status_options[i].hdr_out_str,
+ apr_ltoa(r->pool, t < 1 ? 10 : t));
+ break;
+ }
+ case STAT_OPT_NOTABLE:
+ no_table_report = 1;
+ break;
+ case STAT_OPT_AUTO:
+ ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
+ short_report = 1;
+ break;
+ }
+ }
+
+ i++;
+ }
+ }
+
+ ws_record = apr_palloc(r->pool, sizeof *ws_record);
+
+ for (i = 0; i < server_limit; ++i) {
+#ifdef HAVE_TIMES
+ clock_t proc_tu = 0, proc_ts = 0, proc_tcu = 0, proc_tcs = 0;
+ clock_t tmp_tu, tmp_ts, tmp_tcu, tmp_tcs;
+#endif
+
+ ps_record = ap_get_scoreboard_process(i);
+ if (is_async) {
+ thread_idle_buffer[i] = 0;
+ thread_busy_buffer[i] = 0;
+ }
+ for (j = 0; j < thread_limit; ++j) {
+ int indx = (i * thread_limit) + j;
+
+ ap_copy_scoreboard_worker(ws_record, i, j);
+ res = ws_record->status;
+
+ if ((i >= max_servers || j >= threads_per_child)
+ && (res == SERVER_DEAD))
+ stat_buffer[indx] = status_flags[SERVER_DISABLED];
+ else
+ stat_buffer[indx] = status_flags[res];
+
+ if (!ps_record->quiescing
+ && ps_record->pid) {
+ if (res == SERVER_READY) {
+ if (ps_record->generation == mpm_generation)
+ ready++;
+ if (is_async)
+ thread_idle_buffer[i]++;
+ }
+ else if (res != SERVER_DEAD &&
+ res != SERVER_STARTING &&
+ res != SERVER_IDLE_KILL) {
+ busy++;
+ if (is_async) {
+ if (res == SERVER_GRACEFUL)
+ thread_idle_buffer[i]++;
+ else
+ thread_busy_buffer[i]++;
+ }
+ }
+ }
+
+ /* XXX what about the counters for quiescing/seg faulted
+ * processes? should they be counted or not? GLA
+ */
+ if (ap_extended_status) {
+ lres = ws_record->access_count;
+ bytes = ws_record->bytes_served;
+
+ if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) {
+#ifdef HAVE_TIMES
+ tmp_tu = ws_record->times.tms_utime;
+ tmp_ts = ws_record->times.tms_stime;
+ tmp_tcu = ws_record->times.tms_cutime;
+ tmp_tcs = ws_record->times.tms_cstime;
+
+ if (times_per_thread) {
+ proc_tu += tmp_tu;
+ proc_ts += tmp_ts;
+ proc_tcu += tmp_tcu;
+ proc_tcs += tmp_tcs;
+ }
+ else {
+ if (tmp_tu > proc_tu ||
+ tmp_ts > proc_ts ||
+ tmp_tcu > proc_tcu ||
+ tmp_tcs > proc_tcs) {
+ proc_tu = tmp_tu;
+ proc_ts = tmp_ts;
+ proc_tcu = tmp_tcu;
+ proc_tcs = tmp_tcs;
+ }
+ }
+#endif /* HAVE_TIMES */
+
+ count += lres;
+ bcount += bytes;
+ duration_global += ws_record->duration;
+
+ if (bcount >= KBYTE) {
+ kbcount += (bcount >> 10);
+ bcount = bcount & 0x3ff;
+ }
+ }
+ }
+ }
+#ifdef HAVE_TIMES
+ tu += proc_tu;
+ ts += proc_ts;
+ tcu += proc_tcu;
+ tcs += proc_tcs;
+#endif
+ pid_buffer[i] = ps_record->pid;
+ }
+
+ /* up_time in seconds */
+ up_time = (apr_uint32_t) apr_time_sec(nowtime -
+ ap_scoreboard_image->global->restart_time);
+ ap_get_loadavg(&t);
+
+ if (!short_report) {
+ ap_rputs(DOCTYPE_HTML_3_2
+ "<html><head>\n"
+ "<title>Apache Status</title>\n"
+ "</head><body>\n"
+ "<h1>Apache Server Status for ", r);
+ ap_rvputs(r, ap_escape_html(r->pool, ap_get_server_name(r)),
+ " (via ", r->connection->local_ip,
+ ")</h1>\n\n", NULL);
+ ap_rvputs(r, "<dl><dt>Server Version: ",
+ ap_get_server_description(), "</dt>\n", NULL);
+ ap_rvputs(r, "<dt>Server MPM: ",
+ ap_show_mpm(), "</dt>\n", NULL);
+ ap_rvputs(r, "<dt>Server Built: ",
+ ap_get_server_built(), "\n</dt></dl><hr /><dl>\n", NULL);
+ ap_rvputs(r, "<dt>Current Time: ",
+ ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0),
+ "</dt>\n", NULL);
+ ap_rvputs(r, "<dt>Restart Time: ",
+ ap_ht_time(r->pool,
+ ap_scoreboard_image->global->restart_time,
+ DEFAULT_TIME_FORMAT, 0),
+ "</dt>\n", NULL);
+ ap_rprintf(r, "<dt>Parent Server Config. Generation: %d</dt>\n",
+ ap_state_query(AP_SQ_CONFIG_GEN));
+ ap_rprintf(r, "<dt>Parent Server MPM Generation: %d</dt>\n",
+ (int)mpm_generation);
+ ap_rputs("<dt>Server uptime: ", r);
+ show_time(r, up_time);
+ ap_rputs("</dt>\n", r);
+ ap_rprintf(r, "<dt>Server load: %.2f %.2f %.2f</dt>\n",
+ t.loadavg, t.loadavg5, t.loadavg15);
+ }
+ else {
+ ap_rvputs(r, ap_get_server_name(r), "\n", NULL);
+ ap_rvputs(r, "ServerVersion: ",
+ ap_get_server_description(), "\n", NULL);
+ ap_rvputs(r, "ServerMPM: ",
+ ap_show_mpm(), "\n", NULL);
+ ap_rvputs(r, "Server Built: ",
+ ap_get_server_built(), "\n", NULL);
+ ap_rvputs(r, "CurrentTime: ",
+ ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0),
+ "\n", NULL);
+ ap_rvputs(r, "RestartTime: ",
+ ap_ht_time(r->pool,
+ ap_scoreboard_image->global->restart_time,
+ DEFAULT_TIME_FORMAT, 0),
+ "\n", NULL);
+ ap_rprintf(r, "ParentServerConfigGeneration: %d\n",
+ ap_state_query(AP_SQ_CONFIG_GEN));
+ ap_rprintf(r, "ParentServerMPMGeneration: %d\n",
+ (int)mpm_generation);
+ ap_rprintf(r, "ServerUptimeSeconds: %u\n",
+ up_time);
+ ap_rputs("ServerUptime:", r);
+ show_time(r, up_time);
+ ap_rputs("\n", r);
+ ap_rprintf(r, "Load1: %.2f\nLoad5: %.2f\nLoad15: %.2f\n",
+ t.loadavg, t.loadavg5, t.loadavg15);
+ }
+
+ if (ap_extended_status) {
+ clock_t cpu = gu + gs + gcu + gcs + tu + ts + tcu + tcs;
+ if (short_report) {
+ ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %"
+ APR_OFF_T_FMT "\nTotal Duration: %"
+ APR_TIME_T_FMT "\n",
+ count, kbcount, apr_time_as_msec(duration_global));
+
+#ifdef HAVE_TIMES
+ /* Allow for OS/2 not having CPU stats */
+ ap_rprintf(r, "CPUUser: %g\nCPUSystem: %g\nCPUChildrenUser: %g\nCPUChildrenSystem: %g\n",
+ (gu + tu) / tick, (gs + ts) / tick, (gcu + tcu) / tick, (gcs + tcs) / tick);
+
+ if (cpu)
+ ap_rprintf(r, "CPULoad: %g\n",
+ cpu / tick / up_time * 100.);
+#endif
+
+ ap_rprintf(r, "Uptime: %ld\n", (long) (up_time));
+ if (up_time > 0) {
+ ap_rprintf(r, "ReqPerSec: %g\n",
+ (float) count / (float) up_time);
+
+ ap_rprintf(r, "BytesPerSec: %g\n",
+ KBYTE * (float) kbcount / (float) up_time);
+ }
+ if (count > 0) {
+ ap_rprintf(r, "BytesPerReq: %g\n",
+ KBYTE * (float) kbcount / (float) count);
+ ap_rprintf(r, "DurationPerReq: %g\n",
+ (float) apr_time_as_msec(duration_global) / (float) count);
+ }
+ }
+ else { /* !short_report */
+ ap_rprintf(r, "<dt>Total accesses: %lu - Total Traffic: ", count);
+ format_kbyte_out(r, kbcount);
+ ap_rprintf(r, " - Total Duration: %" APR_TIME_T_FMT "</dt>\n",
+ apr_time_as_msec(duration_global));
+
+#ifdef HAVE_TIMES
+ /* Allow for OS/2 not having CPU stats */
+ ap_rprintf(r, "<dt>CPU Usage: u%g s%g cu%g cs%g",
+ (gu + tu) / tick, (gs + ts) / tick, (gcu + tcu) / tick, (gcs + tcs) / tick);
+
+ if (cpu)
+ ap_rprintf(r, " - %.3g%% CPU load</dt>\n",
+ cpu / tick / up_time * 100.);
+ else
+ ap_rputs("</dt>\n", r);
+#endif
+
+ ap_rputs("<dt>", r);
+ if (up_time > 0) {
+ ap_rprintf(r, "%.3g requests/sec - ",
+ (float) count / (float) up_time);
+
+ format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount
+ / (float) up_time));
+ ap_rputs("/second", r);
+ }
+
+ if (count > 0) {
+ if (up_time > 0)
+ ap_rputs(" - ", r);
+ format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount
+ / (float) count));
+ ap_rprintf(r, "/request - %g ms/request",
+ (float) apr_time_as_msec(duration_global) / (float) count);
+ }
+
+ ap_rputs("</dt>\n", r);
+ } /* short_report */
+ } /* ap_extended_status */
+
+ if (!short_report)
+ ap_rprintf(r, "<dt>%d requests currently being processed, "
+ "%d idle workers</dt>\n", busy, ready);
+ else
+ ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready);
+
+ if (!short_report)
+ ap_rputs("</dl>", r);
+
+ if (is_async) {
+ int write_completion = 0, lingering_close = 0, keep_alive = 0,
+ connections = 0, stopping = 0, procs = 0;
+ /*
+ * These differ from 'busy' and 'ready' in how gracefully finishing
+ * threads are counted. XXX: How to make this clear in the html?
+ */
+ int busy_workers = 0, idle_workers = 0;
+ if (!short_report)
+ ap_rputs("\n\n<table rules=\"all\" cellpadding=\"1%\">\n"
+ "<tr><th rowspan=\"2\">Slot</th>"
+ "<th rowspan=\"2\">PID</th>"
+ "<th rowspan=\"2\">Stopping</th>"
+ "<th colspan=\"2\">Connections</th>\n"
+ "<th colspan=\"2\">Threads</th>"
+ "<th colspan=\"3\">Async connections</th></tr>\n"
+ "<tr><th>total</th><th>accepting</th>"
+ "<th>busy</th><th>idle</th>"
+ "<th>writing</th><th>keep-alive</th><th>closing</th></tr>\n", r);
+ for (i = 0; i < server_limit; ++i) {
+ ps_record = ap_get_scoreboard_process(i);
+ if (ps_record->pid) {
+ connections += ps_record->connections;
+ write_completion += ps_record->write_completion;
+ keep_alive += ps_record->keep_alive;
+ lingering_close += ps_record->lingering_close;
+ busy_workers += thread_busy_buffer[i];
+ idle_workers += thread_idle_buffer[i];
+ procs++;
+ if (ps_record->quiescing) {
+ stopping++;
+ }
+ if (!short_report) {
+ const char *dying = "no";
+ const char *old = "";
+ if (ps_record->quiescing) {
+ dying = "yes";
+ }
+ if (ps_record->generation != mpm_generation)
+ old = " (old gen)";
+ ap_rprintf(r, "<tr><td>%u</td><td>%" APR_PID_T_FMT "</td>"
+ "<td>%s%s</td>"
+ "<td>%u</td><td>%s</td>"
+ "<td>%u</td><td>%u</td>"
+ "<td>%u</td><td>%u</td><td>%u</td>"
+ "</tr>\n",
+ i, ps_record->pid,
+ dying, old,
+ ps_record->connections,
+ ps_record->not_accepting ? "no" : "yes",
+ thread_busy_buffer[i],
+ thread_idle_buffer[i],
+ ps_record->write_completion,
+ ps_record->keep_alive,
+ ps_record->lingering_close);
+ }
+ }
+ }
+ if (!short_report) {
+ ap_rprintf(r, "<tr><td>Sum</td>"
+ "<td>%d</td><td>%d</td>"
+ "<td>%d</td><td>&nbsp;</td>"
+ "<td>%d</td><td>%d</td>"
+ "<td>%d</td><td>%d</td><td>%d</td>"
+ "</tr>\n</table>\n",
+ procs, stopping,
+ connections,
+ busy_workers, idle_workers,
+ write_completion, keep_alive, lingering_close);
+ }
+ else {
+ ap_rprintf(r, "Processes: %d\n"
+ "Stopping: %d\n"
+ "BusyWorkers: %d\n"
+ "IdleWorkers: %d\n"
+ "ConnsTotal: %d\n"
+ "ConnsAsyncWriting: %d\n"
+ "ConnsAsyncKeepAlive: %d\n"
+ "ConnsAsyncClosing: %d\n",
+ procs, stopping,
+ busy_workers, idle_workers,
+ connections,
+ write_completion, keep_alive, lingering_close);
+ }
+ }
+
+ /* send the scoreboard 'table' out */
+ if (!short_report)
+ ap_rputs("<pre>", r);
+ else
+ ap_rputs("Scoreboard: ", r);
+
+ written = 0;
+ for (i = 0; i < server_limit; ++i) {
+ for (j = 0; j < thread_limit; ++j) {
+ int indx = (i * thread_limit) + j;
+ if (stat_buffer[indx] != status_flags[SERVER_DISABLED]) {
+ ap_rputc(stat_buffer[indx], r);
+ if ((written % STATUS_MAXLINE == (STATUS_MAXLINE - 1))
+ && !short_report)
+ ap_rputs("\n", r);
+ written++;
+ }
+ }
+ }
+
+
+ if (short_report)
+ ap_rputs("\n", r);
+ else {
+ ap_rputs("</pre>\n"
+ "<p>Scoreboard Key:<br />\n"
+ "\"<b><code>_</code></b>\" Waiting for Connection, \n"
+ "\"<b><code>S</code></b>\" Starting up, \n"
+ "\"<b><code>R</code></b>\" Reading Request,<br />\n"
+ "\"<b><code>W</code></b>\" Sending Reply, \n"
+ "\"<b><code>K</code></b>\" Keepalive (read), \n"
+ "\"<b><code>D</code></b>\" DNS Lookup,<br />\n"
+ "\"<b><code>C</code></b>\" Closing connection, \n"
+ "\"<b><code>L</code></b>\" Logging, \n"
+ "\"<b><code>G</code></b>\" Gracefully finishing,<br /> \n"
+ "\"<b><code>I</code></b>\" Idle cleanup of worker, \n"
+ "\"<b><code>.</code></b>\" Open slot with no current process<br />\n"
+ "</p>\n", r);
+ if (!ap_extended_status) {
+ int j;
+ int k = 0;
+ ap_rputs("PID Key: <br />\n"
+ "<pre>\n", r);
+ for (i = 0; i < server_limit; ++i) {
+ for (j = 0; j < thread_limit; ++j) {
+ int indx = (i * thread_limit) + j;
+
+ if (stat_buffer[indx] != '.') {
+ ap_rprintf(r, " %" APR_PID_T_FMT
+ " in state: %c ", pid_buffer[i],
+ stat_buffer[indx]);
+
+ if (++k >= 3) {
+ ap_rputs("\n", r);
+ k = 0;
+ } else
+ ap_rputs(",", r);
+ }
+ }
+ }
+
+ ap_rputs("\n"
+ "</pre>\n", r);
+ }
+ }
+
+ if (ap_extended_status && !short_report) {
+ if (no_table_report)
+ ap_rputs("<hr /><h2>Server Details</h2>\n\n", r);
+ else
+ ap_rputs("\n\n<table border=\"0\"><tr>"
+ "<th>Srv</th><th>PID</th><th>Acc</th>"
+ "<th>M</th>"
+#ifdef HAVE_TIMES
+ "<th>CPU\n</th>"
+#endif
+ "<th>SS</th><th>Req</th><th>Dur</th>"
+ "<th>Conn</th><th>Child</th><th>Slot</th>"
+ "<th>Client</th><th>Protocol</th><th>VHost</th>"
+ "<th>Request</th></tr>\n\n", r);
+
+ for (i = 0; i < server_limit; ++i) {
+ for (j = 0; j < thread_limit; ++j) {
+ ap_copy_scoreboard_worker(ws_record, i, j);
+
+ if (ws_record->access_count == 0 &&
+ (ws_record->status == SERVER_READY ||
+ ws_record->status == SERVER_DEAD)) {
+ continue;
+ }
+
+ ps_record = ap_get_scoreboard_process(i);
+
+ if (ws_record->start_time == 0L)
+ req_time = 0L;
+ else
+ req_time = (long)
+ apr_time_as_msec(ws_record->stop_time -
+ ws_record->start_time);
+ if (req_time < 0L)
+ req_time = 0L;
+
+ lres = ws_record->access_count;
+ my_lres = ws_record->my_access_count;
+ conn_lres = ws_record->conn_count;
+ bytes = ws_record->bytes_served;
+ my_bytes = ws_record->my_bytes_served;
+ conn_bytes = ws_record->conn_bytes;
+ duration_slot = ws_record->duration;
+ if (ws_record->pid) { /* MPM sets per-worker pid and generation */
+ worker_pid = ws_record->pid;
+ worker_generation = ws_record->generation;
+ }
+ else {
+ worker_pid = ps_record->pid;
+ worker_generation = ps_record->generation;
+ }
+
+ if (no_table_report) {
+ if (ws_record->status == SERVER_DEAD)
+ ap_rprintf(r,
+ "<b>Server %d-%d</b> (-): %d|%lu|%lu [",
+ i, (int)worker_generation,
+ (int)conn_lres, my_lres, lres);
+ else
+ ap_rprintf(r,
+ "<b>Server %d-%d</b> (%"
+ APR_PID_T_FMT "): %d|%lu|%lu [",
+ i, (int) worker_generation,
+ worker_pid,
+ (int)conn_lres, my_lres, lres);
+
+ switch (ws_record->status) {
+ case SERVER_READY:
+ ap_rputs("Ready", r);
+ break;
+ case SERVER_STARTING:
+ ap_rputs("Starting", r);
+ break;
+ case SERVER_BUSY_READ:
+ ap_rputs("<b>Read</b>", r);
+ break;
+ case SERVER_BUSY_WRITE:
+ ap_rputs("<b>Write</b>", r);
+ break;
+ case SERVER_BUSY_KEEPALIVE:
+ ap_rputs("<b>Keepalive</b>", r);
+ break;
+ case SERVER_BUSY_LOG:
+ ap_rputs("<b>Logging</b>", r);
+ break;
+ case SERVER_BUSY_DNS:
+ ap_rputs("<b>DNS lookup</b>", r);
+ break;
+ case SERVER_CLOSING:
+ ap_rputs("<b>Closing</b>", r);
+ break;
+ case SERVER_DEAD:
+ ap_rputs("Dead", r);
+ break;
+ case SERVER_GRACEFUL:
+ ap_rputs("Graceful", r);
+ break;
+ case SERVER_IDLE_KILL:
+ ap_rputs("Dying", r);
+ break;
+ default:
+ ap_rputs("?STATE?", r);
+ break;
+ }
+
+ ap_rprintf(r, "] "
+#ifdef HAVE_TIMES
+ "u%g s%g cu%g cs%g"
+#endif
+ "\n %ld %ld %" APR_TIME_T_FMT "(",
+#ifdef HAVE_TIMES
+ ws_record->times.tms_utime / tick,
+ ws_record->times.tms_stime / tick,
+ ws_record->times.tms_cutime / tick,
+ ws_record->times.tms_cstime / tick,
+#endif
+ (long)apr_time_sec(nowtime -
+ ws_record->last_used),
+ (long) req_time, apr_time_as_msec(duration_slot));
+
+ format_byte_out(r, conn_bytes);
+ ap_rputs("|", r);
+ format_byte_out(r, my_bytes);
+ ap_rputs("|", r);
+ format_byte_out(r, bytes);
+ ap_rputs(")\n", r);
+ ap_rprintf(r,
+ " <i>%s {%s}</i> <i>(%s)</i> <b>[%s]</b><br />\n\n",
+ ap_escape_html(r->pool,
+ ws_record->client64),
+ ap_escape_html(r->pool,
+ ap_escape_logitem(r->pool,
+ ws_record->request)),
+ ap_escape_html(r->pool,
+ ws_record->protocol),
+ ap_escape_html(r->pool,
+ ws_record->vhost));
+ }
+ else { /* !no_table_report */
+ if (ws_record->status == SERVER_DEAD)
+ ap_rprintf(r,
+ "<tr><td><b>%d-%d</b></td><td>-</td><td>%d/%lu/%lu",
+ i, (int)worker_generation,
+ (int)conn_lres, my_lres, lres);
+ else
+ ap_rprintf(r,
+ "<tr><td><b>%d-%d</b></td><td>%"
+ APR_PID_T_FMT
+ "</td><td>%d/%lu/%lu",
+ i, (int)worker_generation,
+ worker_pid,
+ (int)conn_lres,
+ my_lres, lres);
+
+ switch (ws_record->status) {
+ case SERVER_READY:
+ ap_rputs("</td><td>_", r);
+ break;
+ case SERVER_STARTING:
+ ap_rputs("</td><td><b>S</b>", r);
+ break;
+ case SERVER_BUSY_READ:
+ ap_rputs("</td><td><b>R</b>", r);
+ break;
+ case SERVER_BUSY_WRITE:
+ ap_rputs("</td><td><b>W</b>", r);
+ break;
+ case SERVER_BUSY_KEEPALIVE:
+ ap_rputs("</td><td><b>K</b>", r);
+ break;
+ case SERVER_BUSY_LOG:
+ ap_rputs("</td><td><b>L</b>", r);
+ break;
+ case SERVER_BUSY_DNS:
+ ap_rputs("</td><td><b>D</b>", r);
+ break;
+ case SERVER_CLOSING:
+ ap_rputs("</td><td><b>C</b>", r);
+ break;
+ case SERVER_DEAD:
+ ap_rputs("</td><td>.", r);
+ break;
+ case SERVER_GRACEFUL:
+ ap_rputs("</td><td>G", r);
+ break;
+ case SERVER_IDLE_KILL:
+ ap_rputs("</td><td>I", r);
+ break;
+ default:
+ ap_rputs("</td><td>?", r);
+ break;
+ }
+
+ ap_rprintf(r,
+ "\n</td>"
+#ifdef HAVE_TIMES
+ "<td>%.2f</td>"
+#endif
+ "<td>%ld</td><td>%ld</td><td>%" APR_TIME_T_FMT,
+#ifdef HAVE_TIMES
+ (ws_record->times.tms_utime +
+ ws_record->times.tms_stime +
+ ws_record->times.tms_cutime +
+ ws_record->times.tms_cstime) / tick,
+#endif
+ (long)apr_time_sec(nowtime -
+ ws_record->last_used),
+ (long)req_time, apr_time_as_msec(duration_slot));
+
+ ap_rprintf(r, "</td><td>%-1.1f</td><td>%-2.2f</td><td>%-2.2f\n",
+ (float)conn_bytes / KBYTE, (float) my_bytes / MBYTE,
+ (float)bytes / MBYTE);
+
+ ap_rprintf(r, "</td><td>%s</td><td>%s</td><td nowrap>%s</td>"
+ "<td nowrap>%s</td></tr>\n\n",
+ ap_escape_html(r->pool,
+ ws_record->client64),
+ ap_escape_html(r->pool,
+ ws_record->protocol),
+ ap_escape_html(r->pool,
+ ws_record->vhost),
+ ap_escape_html(r->pool,
+ ap_escape_logitem(r->pool,
+ ws_record->request)));
+ } /* no_table_report */
+ } /* for (j...) */
+ } /* for (i...) */
+
+ if (!no_table_report) {
+ ap_rputs("</table>\n \
+<hr /> \
+<table>\n \
+<tr><th>Srv</th><td>Child Server number - generation</td></tr>\n \
+<tr><th>PID</th><td>OS process ID</td></tr>\n \
+<tr><th>Acc</th><td>Number of accesses this connection / this child / this slot</td></tr>\n \
+<tr><th>M</th><td>Mode of operation</td></tr>\n"
+
+#ifdef HAVE_TIMES
+"<tr><th>CPU</th><td>CPU usage, number of seconds</td></tr>\n"
+#endif
+
+"<tr><th>SS</th><td>Seconds since beginning of most recent request</td></tr>\n \
+<tr><th>Req</th><td>Milliseconds required to process most recent request</td></tr>\n \
+<tr><th>Dur</th><td>Sum of milliseconds required to process all requests</td></tr>\n \
+<tr><th>Conn</th><td>Kilobytes transferred this connection</td></tr>\n \
+<tr><th>Child</th><td>Megabytes transferred this child</td></tr>\n \
+<tr><th>Slot</th><td>Total megabytes transferred this slot</td></tr>\n \
+</table>\n", r);
+ }
+ } /* if (ap_extended_status && !short_report) */
+ else {
+
+ if (!short_report) {
+ ap_rputs("<hr />To obtain a full report with current status "
+ "information you need to use the "
+ "<code>ExtendedStatus On</code> directive.\n", r);
+ }
+ }
+
+ {
+ /* Run extension hooks to insert extra content. */
+ int flags =
+ (short_report ? AP_STATUS_SHORT : 0) |
+ (no_table_report ? AP_STATUS_NOTABLE : 0) |
+ (ap_extended_status ? AP_STATUS_EXTENDED : 0);
+
+ ap_run_status_hook(r, flags);
+ }
+
+ if (!short_report) {
+ ap_rputs(ap_psignature("<hr />\n",r), r);
+ ap_rputs("</body></html>\n", r);
+ }
+
+ return 0;
+}
+
+static int status_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
+{
+ /* When mod_status is loaded, default our ExtendedStatus to 'on'
+ * other modules which prefer verbose scoreboards may play a similar game.
+ * If left to their own requirements, mpm modules can make do with simple
+ * scoreboard entries.
+ */
+ ap_extended_status = 1;
+ return OK;
+}
+
+static int status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
+ server_rec *s)
+{
+ status_flags[SERVER_DEAD] = '.'; /* We don't want to assume these are in */
+ status_flags[SERVER_READY] = '_'; /* any particular order in scoreboard.h */
+ status_flags[SERVER_STARTING] = 'S';
+ status_flags[SERVER_BUSY_READ] = 'R';
+ status_flags[SERVER_BUSY_WRITE] = 'W';
+ status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
+ status_flags[SERVER_BUSY_LOG] = 'L';
+ status_flags[SERVER_BUSY_DNS] = 'D';
+ status_flags[SERVER_CLOSING] = 'C';
+ status_flags[SERVER_GRACEFUL] = 'G';
+ status_flags[SERVER_IDLE_KILL] = 'I';
+ status_flags[SERVER_DISABLED] = ' ';
+ ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+ ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
+ ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child);
+ /* work around buggy MPMs */
+ if (threads_per_child == 0)
+ threads_per_child = 1;
+ ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_servers);
+ ap_mpm_query(AP_MPMQ_IS_ASYNC, &is_async);
+ return OK;
+}
+
+#ifdef HAVE_TIMES
+static void status_child_init(apr_pool_t *p, server_rec *s)
+{
+ child_pid = getpid();
+}
+#endif
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_hook_handler(status_handler, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_pre_config(status_pre_config, NULL, NULL, APR_HOOK_LAST);
+ ap_hook_post_config(status_init, NULL, NULL, APR_HOOK_MIDDLE);
+#ifdef HAVE_TIMES
+ ap_hook_child_init(status_child_init, NULL, NULL, APR_HOOK_MIDDLE);
+#endif
+}
+
+AP_DECLARE_MODULE(status) =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ NULL, /* command table */
+ register_hooks /* register_hooks */
+};
diff --git a/modules/generators/mod_status.dep b/modules/generators/mod_status.dep
new file mode 100644
index 0000000..7ec631b
--- /dev/null
+++ b/modules/generators/mod_status.dep
@@ -0,0 +1,60 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_status.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_status.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_mpm.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_core.h"\
+ "..\..\include\http_log.h"\
+ "..\..\include\http_main.h"\
+ "..\..\include\http_protocol.h"\
+ "..\..\include\httpd.h"\
+ "..\..\include\os.h"\
+ "..\..\include\scoreboard.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\include\util_script.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.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-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_hash.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+ ".\mod_status.h"\
+
diff --git a/modules/generators/mod_status.dsp b/modules/generators/mod_status.dsp
new file mode 100644
index 0000000..4596640
--- /dev/null
+++ b/modules/generators/mod_status.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_status" - 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_status - 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_status.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_status.mak" CFG="mod_status - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_status - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_status - 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_status - 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 "STATUS_DECLARE_EXPORT" /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 "STATUS_DECLARE_EXPORT" /Fd"Release\mod_status_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_status.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_status.so" /d LONG_NAME="status_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_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_status.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_status - 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" /D "STATUS_DECLARE_EXPORT" /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 "STATUS_DECLARE_EXPORT" /Fd"Debug\mod_status_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_status.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_status.so" /d LONG_NAME="status_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_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_status.so" /base:@..\..\os\win32\BaseAddr.ref,mod_status.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_status.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_status - Win32 Release"
+# Name "mod_status - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_status.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/generators/mod_status.exp b/modules/generators/mod_status.exp
new file mode 100644
index 0000000..5438093
--- /dev/null
+++ b/modules/generators/mod_status.exp
@@ -0,0 +1 @@
+status_module
diff --git a/modules/generators/mod_status.h b/modules/generators/mod_status.h
new file mode 100644
index 0000000..721b96d
--- /dev/null
+++ b/modules/generators/mod_status.h
@@ -0,0 +1,64 @@
+/* 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.
+ */
+
+/**
+ * @file mod_status.h
+ * @brief Status Report Extension Module to Apache
+ *
+ * @defgroup MOD_STATUS mod_status
+ * @ingroup APACHE_MODS
+ * @{
+ */
+
+#ifndef MOD_STATUS_H
+#define MOD_STATUS_H
+
+#include "ap_config.h"
+#include "httpd.h"
+
+#define AP_STATUS_SHORT (0x1) /* short, non-HTML report requested */
+#define AP_STATUS_NOTABLE (0x2) /* HTML report without tables */
+#define AP_STATUS_EXTENDED (0x4) /* detailed report */
+
+#if !defined(WIN32)
+#define STATUS_DECLARE(type) type
+#define STATUS_DECLARE_NONSTD(type) type
+#define STATUS_DECLARE_DATA
+#elif defined(STATUS_DECLARE_STATIC)
+#define STATUS_DECLARE(type) type __stdcall
+#define STATUS_DECLARE_NONSTD(type) type
+#define STATUS_DECLARE_DATA
+#elif defined(STATUS_DECLARE_EXPORT)
+#define STATUS_DECLARE(type) __declspec(dllexport) type __stdcall
+#define STATUS_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define STATUS_DECLARE_DATA __declspec(dllexport)
+#else
+#define STATUS_DECLARE(type) __declspec(dllimport) type __stdcall
+#define STATUS_DECLARE_NONSTD(type) __declspec(dllimport) type
+#define STATUS_DECLARE_DATA __declspec(dllimport)
+#endif
+
+/* Optional hooks which can insert extra content into the mod_status
+ * output. FLAGS will be set to the bitwise OR of any of the
+ * AP_STATUS_* flags.
+ *
+ * Implementations of this hook should generate content using
+ * functions in the ap_rputs/ap_rprintf family; each hook should
+ * return OK or DECLINED. */
+APR_DECLARE_EXTERNAL_HOOK(ap, STATUS, int, status_hook,
+ (request_rec *r, int flags))
+#endif
+/** @} */
diff --git a/modules/generators/mod_status.mak b/modules/generators/mod_status.mak
new file mode 100644
index 0000000..168bbc8
--- /dev/null
+++ b/modules/generators/mod_status.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_status.dsp
+!IF "$(CFG)" == ""
+CFG=mod_status - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_status - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_status - Win32 Release" && "$(CFG)" != "mod_status - 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_status.mak" CFG="mod_status - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_status - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_status - 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_status - 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_status.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_status.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_status.obj"
+ -@erase "$(INTDIR)\mod_status.res"
+ -@erase "$(INTDIR)\mod_status_src.idb"
+ -@erase "$(INTDIR)\mod_status_src.pdb"
+ -@erase "$(OUTDIR)\mod_status.exp"
+ -@erase "$(OUTDIR)\mod_status.lib"
+ -@erase "$(OUTDIR)\mod_status.pdb"
+ -@erase "$(OUTDIR)\mod_status.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 "STATUS_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_status_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_status.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_status.so" /d LONG_NAME="status_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_status.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_status.pdb" /debug /out:"$(OUTDIR)\mod_status.so" /implib:"$(OUTDIR)\mod_status.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_status.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_status.obj" \
+ "$(INTDIR)\mod_status.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_status.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_status.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_status.so"
+ if exist .\Release\mod_status.so.manifest mt.exe -manifest .\Release\mod_status.so.manifest -outputresource:.\Release\mod_status.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_status - 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_status.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_status.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_status.obj"
+ -@erase "$(INTDIR)\mod_status.res"
+ -@erase "$(INTDIR)\mod_status_src.idb"
+ -@erase "$(INTDIR)\mod_status_src.pdb"
+ -@erase "$(OUTDIR)\mod_status.exp"
+ -@erase "$(OUTDIR)\mod_status.lib"
+ -@erase "$(OUTDIR)\mod_status.pdb"
+ -@erase "$(OUTDIR)\mod_status.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 "STATUS_DECLARE_EXPORT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_status_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_status.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_status.so" /d LONG_NAME="status_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_status.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_status.pdb" /debug /out:"$(OUTDIR)\mod_status.so" /implib:"$(OUTDIR)\mod_status.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_status.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_status.obj" \
+ "$(INTDIR)\mod_status.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_status.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_status.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_status.so"
+ if exist .\Debug\mod_status.so.manifest mt.exe -manifest .\Debug\mod_status.so.manifest -outputresource:.\Debug\mod_status.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_status.dep")
+!INCLUDE "mod_status.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_status.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_status - Win32 Release" || "$(CFG)" == "mod_status - Win32 Debug"
+
+!IF "$(CFG)" == "mod_status - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_status - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_status - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_status - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\generators"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\generators"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_status - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ELSEIF "$(CFG)" == "mod_status - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\generators"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\generators"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_status - Win32 Release"
+
+
+"$(INTDIR)\mod_status.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_status.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_status.so" /d LONG_NAME="status_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_status - Win32 Debug"
+
+
+"$(INTDIR)\mod_status.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_status.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_status.so" /d LONG_NAME="status_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_status.c
+
+"$(INTDIR)\mod_status.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/generators/mod_suexec.c b/modules/generators/mod_suexec.c
new file mode 100644
index 0000000..a71b0a8
--- /dev/null
+++ b/modules/generators/mod_suexec.c
@@ -0,0 +1,139 @@
+/* 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_core.h"
+#include "http_log.h"
+#include "http_request.h"
+#include "apr_strings.h"
+#include "unixd.h"
+#include "mpm_common.h"
+#include "mod_suexec.h"
+
+module AP_MODULE_DECLARE_DATA suexec_module;
+
+/*
+ * Create a configuration specific to this module for a server or directory
+ * location, and fill it with the default settings.
+ */
+static void *mkconfig(apr_pool_t *p)
+{
+ suexec_config_t *cfg = apr_palloc(p, sizeof(suexec_config_t));
+
+ cfg->active = 0;
+ return cfg;
+}
+
+/*
+ * Respond to a callback to create configuration record for a server or
+ * vhost environment.
+ */
+static void *create_mconfig_for_server(apr_pool_t *p, server_rec *s)
+{
+ return mkconfig(p);
+}
+
+/*
+ * Respond to a callback to create a config record for a specific directory.
+ */
+static void *create_mconfig_for_directory(apr_pool_t *p, char *dir)
+{
+ return mkconfig(p);
+}
+
+static const char *set_suexec_ugid(cmd_parms *cmd, void *mconfig,
+ const char *uid, const char *gid)
+{
+ suexec_config_t *cfg = (suexec_config_t *) mconfig;
+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT);
+
+ if (err != NULL) {
+ return err;
+ }
+
+ if (!ap_unixd_config.suexec_enabled) {
+ return apr_pstrcat(cmd->pool, "SuexecUserGroup configured, but "
+ "suEXEC is disabled: ",
+ ap_unixd_config.suexec_disabled_reason, NULL);
+ }
+
+ cfg->ugid.uid = ap_uname2id(uid);
+ cfg->ugid.gid = ap_gname2id(gid);
+ cfg->ugid.userdir = 0;
+ cfg->active = 1;
+
+ return NULL;
+}
+
+static ap_unix_identity_t *get_suexec_id_doer(const request_rec *r)
+{
+ suexec_config_t *cfg =
+ (suexec_config_t *) ap_get_module_config(r->per_dir_config, &suexec_module);
+
+ return cfg->active ? &cfg->ugid : NULL;
+}
+
+#define SUEXEC_POST_CONFIG_USERDATA "suexec_post_config_userdata"
+static int suexec_post_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ void *reported;
+
+ apr_pool_userdata_get(&reported, SUEXEC_POST_CONFIG_USERDATA,
+ s->process->pool);
+
+ if ((reported == NULL) && ap_unixd_config.suexec_enabled) {
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(01232)
+ "suEXEC mechanism enabled (wrapper: %s)", SUEXEC_BIN);
+
+ apr_pool_userdata_set((void *)1, SUEXEC_POST_CONFIG_USERDATA,
+ apr_pool_cleanup_null, s->process->pool);
+ }
+
+ return OK;
+}
+#undef SUEXEC_POST_CONFIG_USERDATA
+
+/*
+ * Define the directives specific to this module. This structure is referenced
+ * later by the 'module' structure.
+ */
+static const command_rec suexec_cmds[] =
+{
+ /* XXX - Another important reason not to allow this in .htaccess is that
+ * the ap_[ug]name2id() is not thread-safe */
+ AP_INIT_TAKE2("SuexecUserGroup", set_suexec_ugid, NULL, RSRC_CONF,
+ "User and group for spawned processes"),
+ { NULL }
+};
+
+static void suexec_hooks(apr_pool_t *p)
+{
+ ap_hook_get_suexec_identity(get_suexec_id_doer,NULL,NULL,APR_HOOK_MIDDLE);
+ ap_hook_post_config(suexec_post_config,NULL,NULL,APR_HOOK_MIDDLE);
+}
+
+AP_DECLARE_MODULE(suexec) =
+{
+ STANDARD20_MODULE_STUFF,
+ create_mconfig_for_directory, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ create_mconfig_for_server, /* server config */
+ NULL, /* merge server config */
+ suexec_cmds, /* command table */
+ suexec_hooks /* register hooks */
+};
diff --git a/modules/generators/mod_suexec.h b/modules/generators/mod_suexec.h
new file mode 100644
index 0000000..80e2504
--- /dev/null
+++ b/modules/generators/mod_suexec.h
@@ -0,0 +1,33 @@
+/* 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.
+ */
+
+/**
+ * @file mod_suexec.h
+ * @brief SuExec Extension Module for Apache
+ *
+ * @defgroup MOD_SUEXEC mod_suexec
+ * @ingroup APACHE_MODS
+ * @{
+ */
+
+#include "unixd.h"
+
+typedef struct {
+ ap_unix_identity_t ugid;
+ int active;
+} suexec_config_t;
+
+/** @}*/