diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-07 02:04:06 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-07 02:04:06 +0000 |
commit | 5dff2d61cc1c27747ee398e04d8e02843aabb1f8 (patch) | |
tree | a67c336b406c8227bac912beb74a1ad3cdc55100 /modules/loggers | |
parent | Initial commit. (diff) | |
download | apache2-upstream.tar.xz apache2-upstream.zip |
Adding upstream version 2.4.38.upstream/2.4.38upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
26 files changed, 5948 insertions, 0 deletions
diff --git a/modules/loggers/.indent.pro b/modules/loggers/.indent.pro new file mode 100644 index 0000000..a9fbe9f --- /dev/null +++ b/modules/loggers/.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/loggers/Makefile.in b/modules/loggers/Makefile.in new file mode 100644 index 0000000..167b343 --- /dev/null +++ b/modules/loggers/Makefile.in @@ -0,0 +1,3 @@ + +include $(top_srcdir)/build/special.mk + diff --git a/modules/loggers/NWGNUforensic b/modules/loggers/NWGNUforensic new file mode 100644 index 0000000..c55f036 --- /dev/null +++ b/modules/loggers/NWGNUforensic @@ -0,0 +1,258 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(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 = forensic + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Forensic Logging Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = Forensic 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)/forensic.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_log_forensic.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 = \ + log_forensic_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 + $(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/loggers/NWGNUlogdebug b/modules/loggers/NWGNUlogdebug new file mode 100644 index 0000000..e92839a --- /dev/null +++ b/modules/loggers/NWGNUlogdebug @@ -0,0 +1,258 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(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 = logdebug + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Debug Logging Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = Logdbg Module + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/mod_log_debug.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 = \ + log_debug_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 + $(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/loggers/NWGNUmakefile b/modules/loggers/NWGNUmakefile new file mode 100644 index 0000000..6154bf1 --- /dev/null +++ b/modules/loggers/NWGNUmakefile @@ -0,0 +1,247 @@ +# +# 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)/modlogio.nlm \ + $(OBJDIR)/forensic.nlm \ + $(OBJDIR)/logdebug.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/loggers/NWGNUmodlogio b/modules/loggers/NWGNUmodlogio new file mode 100644 index 0000000..fa376db --- /dev/null +++ b/modules/loggers/NWGNUmodlogio @@ -0,0 +1,258 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(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 = logio + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) IO Logging Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = Logio 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)/modlogio.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_logio.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 = \ + logio_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 + $(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/loggers/config.m4 b/modules/loggers/config.m4 new file mode 100644 index 0000000..762e773 --- /dev/null +++ b/modules/loggers/config.m4 @@ -0,0 +1,20 @@ +dnl modules enabled in this directory by default + +dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) + +APACHE_MODPATH_INIT(loggers) + +APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes) +APACHE_MODULE(log_debug, configurable debug logging, , , most) +APACHE_MODULE(log_forensic, forensic logging) + +if test "x$enable_log_forensic" != "xno"; then + # mod_log_forensic needs test_char.h + APR_ADDTO(INCLUDES, [-I\$(top_builddir)/server]) +fi + +APACHE_MODULE(logio, input and output logging, , , most) + +APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) + +APACHE_MODPATH_FINISH diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c new file mode 100644 index 0000000..4270b3f --- /dev/null +++ b/modules/loggers/mod_log_config.c @@ -0,0 +1,1858 @@ +/* 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. + */ + +/* + * Modified by djm@va.pubnix.com: + * If no TransferLog is given explicitly, decline to log. + * + * This is module implements the TransferLog directive (same as the + * common log module), and additional directives, LogFormat and CustomLog. + * + * + * Syntax: + * + * TransferLog fn Logs transfers to fn in standard log format, unless + * a custom format is set with LogFormat + * LogFormat format Set a log format from TransferLog files + * CustomLog fn format + * Log to file fn with format given by the format + * argument + * + * There can be any number of TransferLog and CustomLog + * commands. Each request will be logged to _ALL_ the + * named files, in the appropriate format. + * + * If no TransferLog or CustomLog directive appears in a VirtualHost, + * the request will be logged to the log file(s) defined outside + * the virtual host section. If a TransferLog or CustomLog directive + * appears in the VirtualHost section, the log files defined outside + * the VirtualHost will _not_ be used. This makes this module compatible + * with the CLF and config log modules, where the use of TransferLog + * inside the VirtualHost section overrides its use outside. + * + * Examples: + * + * TransferLog logs/access_log + * <VirtualHost> + * LogFormat "... custom format ..." + * TransferLog log/virtual_only + * CustomLog log/virtual_useragents "%t %{user-agent}i" + * </VirtualHost> + * + * This will log using CLF to access_log any requests handled by the + * main server, while any requests to the virtual host will be logged + * with the "... custom format..." to virtual_only _AND_ using + * the custom user-agent log to virtual_useragents. + * + * Note that the NCSA referer and user-agent logs are easily added with + * CustomLog: + * CustomLog logs/referer "%{referer}i -> %U" + * CustomLog logs/agent "%{user-agent}i" + * + * RefererIgnore functionality can be obtained with conditional + * logging (SetEnvIf and CustomLog ... env=!VAR). + * + * But using this method allows much easier modification of the + * log format, e.g. to log hosts along with UA: + * CustomLog logs/referer "%{referer}i %U %h" + * + * The argument to LogFormat and CustomLog is a string, which can include + * literal characters copied into the log files, and '%' directives as + * follows: + * + * %...B: bytes sent, excluding HTTP headers. + * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-' + * when no bytes where sent (rather than a '0'. + * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR + * %...{FOOBAR}e: The contents of the environment variable FOOBAR + * %...f: filename + * %...h: remote host + * %...a: remote IP-address + * %...A: local IP-address + * %...{Foobar}i: The contents of Foobar: header line(s) in the request + * sent to the client. + * %...k: number of keepalive requests served over this connection + * %...l: remote logname (from identd, if supplied) + * %...{Foobar}n: The contents of note "Foobar" from another module. + * %...{Foobar}o: The contents of Foobar: header line(s) in the reply. + * %...p: the canonical port for the server + * %...{format}p: the canonical port for the server, or the actual local + * or remote port + * %...P: the process ID of the child that serviced the request. + * %...{format}P: the process ID or thread ID of the child/thread that + * serviced the request + * %...r: first line of request + * %...s: status. For requests that got internally redirected, this + * is status of the *original* request --- %...>s for the last. + * %...t: time, in common log format time format + * %...{format}t: The time, in the form given by format, which should + * be in strftime(3) format. + * %...T: the time taken to serve the request, in seconds. + * %...{s}T: the time taken to serve the request, in seconds, same as %T. + * %...{us}T: the time taken to serve the request, in micro seconds, same as %D. + * %...{ms}T: the time taken to serve the request, in milliseconds. + * %...D: the time taken to serve the request, in micro seconds. + * %...u: remote user (from auth; may be bogus if return status (%s) is 401) + * %...U: the URL path requested. + * %...v: the configured name of the server (i.e. which virtual host?) + * %...V: the server name according to the UseCanonicalName setting + * %...m: the request method + * %...H: the request protocol + * %...q: the query string prepended by "?", or empty if no query string + * %...X: Status of the connection. + * 'X' = connection aborted before the response completed. + * '+' = connection may be kept alive after the response is sent. + * '-' = connection will be closed after the response is sent. + * (This directive was %...c in late versions of Apache 1.3, but + * this conflicted with the historical ssl %...{var}c syntax.) + * %...L: Log-Id of the Request (or '-' if none) + * %...{c}L: Log-Id of the Connection (or '-' if none) + * + * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can + * indicate conditions for inclusion of the item (which will cause it + * to be replaced with '-' if the condition is not met). Note that + * there is no escaping performed on the strings from %r, %...i and + * %...o; some with long memories may remember that I thought this was + * a bad idea, once upon a time, and I'm still not comfortable with + * it, but it is difficult to see how to "do the right thing" with all + * of '%..i', unless we URL-escape everything and break with CLF. + * + * The forms of condition are a list of HTTP status codes, which may + * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs + * User-agent: on 400 errors and 501 errors (Bad Request, Not + * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all + * requests which did *not* return some sort of normal status. + * + * The default LogFormat reproduces CLF; see below. + * + * The way this is supposed to work with virtual hosts is as follows: + * a virtual host can have its own LogFormat, or its own TransferLog. + * If it doesn't have its own LogFormat, it inherits from the main + * server. If it doesn't have its own TransferLog, it writes to the + * same descriptor (meaning the same process for "| ..."). + * + * --- rst */ + +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_hash.h" +#include "apr_optional.h" +#include "apr_anylock.h" + +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#include "ap_config.h" +#include "mod_log_config.h" +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" /* For REMOTE_NAME */ +#include "http_log.h" +#include "http_protocol.h" +#include "util_time.h" +#include "ap_mpm.h" + +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" + +module AP_MODULE_DECLARE_DATA log_config_module; + + +static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE); +static apr_fileperms_t xfer_perms = APR_OS_DEFAULT; +static apr_hash_t *log_hash; +static apr_status_t ap_default_log_writer(request_rec *r, + void *handle, + const char **strs, + int *strl, + int nelts, + apr_size_t len); +static apr_status_t ap_buffered_log_writer(request_rec *r, + void *handle, + const char **strs, + int *strl, + int nelts, + apr_size_t len); +static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name); +static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name); + +static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle); +static ap_log_writer *ap_log_set_writer(ap_log_writer *handle); +static ap_log_writer *log_writer = ap_default_log_writer; +static ap_log_writer_init *log_writer_init = ap_default_log_writer_init; +static int buffered_logs = 0; /* default unbuffered */ +static apr_array_header_t *all_buffered_logs = NULL; + +/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is + * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512 + * is guaranteed. So we'll just guess 512 in the event the system + * doesn't have this. Now, for file writes there is actually no limit, + * the entire write is atomic. Whether all systems implement this + * correctly is another question entirely ... so we'll just use PIPE_BUF + * because it's probably a good guess as to what is implemented correctly + * everywhere. + */ +#ifdef PIPE_BUF +#define LOG_BUFSIZE PIPE_BUF +#else +#define LOG_BUFSIZE (512) +#endif + +/* + * multi_log_state is our per-(virtual)-server configuration. We store + * an array of the logs we are going to use, each of type config_log_state. + * If a default log format is given by LogFormat, store in default_format + * (backward compat. with mod_log_config). We also store for each virtual + * server a pointer to the logs specified for the main server, so that if this + * vhost has no logs defined, we can use the main server's logs instead. + * + * So, for the main server, config_logs contains a list of the log files + * and server_config_logs is empty. For a vhost, server_config_logs + * points to the same array as config_logs in the main server, and + * config_logs points to the array of logs defined inside this vhost, + * which might be empty. + */ + +typedef struct { + const char *default_format_string; + apr_array_header_t *default_format; + apr_array_header_t *config_logs; + apr_array_header_t *server_config_logs; + apr_table_t *formats; +} multi_log_state; + +/* + * config_log_state holds the status of a single log file. fname might + * be NULL, which means this module does no logging for this + * request. format might be NULL, in which case the default_format + * from the multi_log_state should be used, or if that is NULL as + * well, use the CLF. + * log_writer is NULL before the log file is opened and is + * set to a opaque structure (usually a fd) after it is opened. + + */ +typedef struct { + apr_file_t *handle; + apr_size_t outcnt; + char outbuf[LOG_BUFSIZE]; + apr_anylock_t mutex; +} buffered_log; + +typedef struct { + const char *fname; + const char *format_string; + apr_array_header_t *format; + void *log_writer; + char *condition_var; + int inherit; + ap_expr_info_t *condition_expr; + /** place of definition or NULL if already checked */ + const ap_directive_t *directive; +} config_log_state; + +/* + * log_request_state holds request specific log data that is not + * part of the request_rec. + */ +typedef struct { + apr_time_t request_end_time; +} log_request_state; + +/* + * Format items... + * Note that many of these could have ap_sprintfs replaced with static buffers. + */ + +typedef struct { + ap_log_handler_fn_t *func; + char *arg; + int condition_sense; + int want_orig; + apr_array_header_t *conditions; +} log_format_item; + +static char *pfmt(apr_pool_t *p, int i) +{ + if (i <= 0) { + return "-"; + } + else { + return apr_itoa(p, i); + } +} + +static const char *constant_item(request_rec *dummy, char *stuff) +{ + return stuff; +} + +static const char *log_remote_host(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection, + r->per_dir_config, + REMOTE_NAME, NULL)); +} + +static const char *log_remote_address(request_rec *r, char *a) +{ + if (a && !strcmp(a, "c")) { + return r->connection->client_ip; + } + else { + return r->useragent_ip; + } +} + +static const char *log_local_address(request_rec *r, char *a) +{ + return r->connection->local_ip; +} + +static const char *log_remote_logname(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, ap_get_remote_logname(r)); +} + +static const char *log_remote_user(request_rec *r, char *a) +{ + char *rvalue = r->user; + + if (rvalue == NULL) { + rvalue = "-"; + } + else if (strlen(rvalue) == 0) { + rvalue = "\"\""; + } + else { + rvalue = ap_escape_logitem(r->pool, rvalue); + } + + return rvalue; +} + +static const char *log_request_line(request_rec *r, char *a) +{ + /* NOTE: If the original request contained a password, we + * re-write the request line here to contain XXXXXX instead: + * (note the truncation before the protocol string for HTTP/0.9 requests) + * (note also that r->the_request contains the unmodified request) + */ + return ap_escape_logitem(r->pool, + (r->parsed_uri.password) + ? apr_pstrcat(r->pool, r->method, " ", + apr_uri_unparse(r->pool, + &r->parsed_uri, 0), + r->assbackwards ? NULL : " ", + r->protocol, NULL) + : r->the_request); +} + +static const char *log_request_file(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, r->filename); +} +static const char *log_request_uri(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, r->uri); +} +static const char *log_request_method(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, r->method); +} +static const char *log_log_id(request_rec *r, char *a) +{ + if (a && !strcmp(a, "c")) { + return r->connection->log_id ? r->connection->log_id : "-"; + } + else { + return r->log_id ? r->log_id : "-"; + } +} +static const char *log_request_protocol(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, r->protocol); +} +static const char *log_request_query(request_rec *r, char *a) +{ + return (r->args) ? apr_pstrcat(r->pool, "?", + ap_escape_logitem(r->pool, r->args), NULL) + : ""; +} +static const char *log_status(request_rec *r, char *a) +{ + return pfmt(r->pool, r->status); +} + +static const char *log_handler(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, r->handler); +} + +static const char *clf_log_bytes_sent(request_rec *r, char *a) +{ + if (!r->sent_bodyct || !r->bytes_sent) { + return "-"; + } + else { + return apr_off_t_toa(r->pool, r->bytes_sent); + } +} + +static const char *log_bytes_sent(request_rec *r, char *a) +{ + if (!r->sent_bodyct || !r->bytes_sent) { + return "0"; + } + else { + return apr_off_t_toa(r->pool, r->bytes_sent); + } +} + + +static const char *log_header_in(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a)); +} + +static const char *log_trailer_in(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->trailers_in, a)); +} + + +static APR_INLINE char *find_multiple_headers(apr_pool_t *pool, + const apr_table_t *table, + const char *key) +{ + const apr_array_header_t *elts; + const apr_table_entry_t *t_elt; + const apr_table_entry_t *t_end; + apr_size_t len; + struct sle { + struct sle *next; + const char *value; + apr_size_t len; + } *result_list, *rp; + + elts = apr_table_elts(table); + + if (!elts->nelts) { + return NULL; + } + + t_elt = (const apr_table_entry_t *)elts->elts; + t_end = t_elt + elts->nelts; + len = 1; /* \0 */ + result_list = rp = NULL; + + do { + if (!strcasecmp(t_elt->key, key)) { + if (!result_list) { + result_list = rp = apr_palloc(pool, sizeof(*rp)); + } + else { + rp = rp->next = apr_palloc(pool, sizeof(*rp)); + len += 2; /* ", " */ + } + + rp->next = NULL; + rp->value = t_elt->val; + rp->len = strlen(rp->value); + + len += rp->len; + } + ++t_elt; + } while (t_elt < t_end); + + if (result_list) { + char *result = apr_palloc(pool, len); + char *cp = result; + + rp = result_list; + while (rp) { + if (rp != result_list) { + *cp++ = ','; + *cp++ = ' '; + } + memcpy(cp, rp->value, rp->len); + cp += rp->len; + rp = rp->next; + } + *cp = '\0'; + + return result; + } + + return NULL; +} + +static const char *log_header_out(request_rec *r, char *a) +{ + const char *cp = NULL; + + if (!strcasecmp(a, "Content-type") && r->content_type) { + cp = ap_field_noparam(r->pool, r->content_type); + } + else if (!strcasecmp(a, "Set-Cookie")) { + cp = find_multiple_headers(r->pool, r->headers_out, a); + } + else { + cp = apr_table_get(r->headers_out, a); + } + + return ap_escape_logitem(r->pool, cp); +} + +static const char *log_trailer_out(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->trailers_out, a)); +} + +static const char *log_note(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->notes, a)); +} +static const char *log_env_var(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->subprocess_env, a)); +} + +static const char *log_cookie(request_rec *r, char *a) +{ + const char *cookies_entry; + + /* + * This supports Netscape version 0 cookies while being tolerant to + * some properties of RFC2109/2965 version 1 cookies: + * - case-insensitive match of cookie names + * - white space between the tokens + * It does not support the following version 1 features: + * - quoted strings as cookie values + * - commas to separate cookies + */ + + if ((cookies_entry = apr_table_get(r->headers_in, "Cookie"))) { + char *cookie, *last1, *last2; + char *cookies = apr_pstrdup(r->pool, cookies_entry); + + while ((cookie = apr_strtok(cookies, ";", &last1))) { + char *name = apr_strtok(cookie, "=", &last2); + /* last2 points to the next char following an '=' delim, + or the trailing NUL char of the string */ + char *value = last2; + if (name && *name && value && *value) { + char *last = value - 2; + /* Move past leading WS */ + name += strspn(name, " \t"); + while (last >= name && apr_isspace(*last)) { + *last = '\0'; + --last; + } + + if (!strcasecmp(name, a)) { + /* last1 points to the next char following the ';' delim, + or the trailing NUL char of the string */ + last = last1 - (*last1 ? 2 : 1); + /* Move past leading WS */ + value += strspn(value, " \t"); + while (last >= value && apr_isspace(*last)) { + *last = '\0'; + --last; + } + + return ap_escape_logitem(r->pool, value); + } + } + /* Iterate the remaining tokens using apr_strtok(NULL, ...) */ + cookies = NULL; + } + } + return NULL; +} + +static const char *log_request_time_custom(request_rec *r, char *a, + apr_time_exp_t *xt) +{ + apr_size_t retcode; + char tstr[MAX_STRING_LEN]; + apr_strftime(tstr, &retcode, sizeof(tstr), a, xt); + return apr_pstrdup(r->pool, tstr); +} + +#define DEFAULT_REQUEST_TIME_SIZE 32 +typedef struct { + unsigned t; + char timestr[DEFAULT_REQUEST_TIME_SIZE]; + unsigned t_validate; +} cached_request_time; + +#define TIME_FMT_CUSTOM 0 +#define TIME_FMT_CLF 1 +#define TIME_FMT_ABS_SEC 2 +#define TIME_FMT_ABS_MSEC 3 +#define TIME_FMT_ABS_USEC 4 +#define TIME_FMT_ABS_MSEC_FRAC 5 +#define TIME_FMT_ABS_USEC_FRAC 6 + +#define TIME_CACHE_SIZE 4 +#define TIME_CACHE_MASK 3 +static cached_request_time request_time_cache[TIME_CACHE_SIZE]; + +static apr_time_t get_request_end_time(request_rec *r) +{ + log_request_state *state = (log_request_state *)ap_get_module_config(r->request_config, + &log_config_module); + if (!state) { + state = apr_pcalloc(r->pool, sizeof(log_request_state)); + ap_set_module_config(r->request_config, &log_config_module, state); + } + if (state->request_end_time == 0) { + state->request_end_time = apr_time_now(); + } + return state->request_end_time; +} + + +static const char *log_request_time(request_rec *r, char *a) +{ + apr_time_exp_t xt; + apr_time_t request_time = r->request_time; + int fmt_type = TIME_FMT_CUSTOM; + char *fmt = a; + + if (fmt && *fmt) { + if (!strncmp(fmt, "begin", 5)) { + fmt += 5; + if (!*fmt) { + fmt_type = TIME_FMT_CLF; + } + else if (*fmt == ':') { + fmt++; + a = fmt; + } + } + else if (!strncmp(fmt, "end", 3)) { + fmt += 3; + if (!*fmt) { + request_time = get_request_end_time(r); + fmt_type = TIME_FMT_CLF; + } + else if (*fmt == ':') { + fmt++; + a = fmt; + request_time = get_request_end_time(r); + } + } + if (!strncmp(fmt, "msec", 4)) { + fmt += 4; + if (!*fmt) { + fmt_type = TIME_FMT_ABS_MSEC; + } + else if (!strcmp(fmt, "_frac")) { + fmt_type = TIME_FMT_ABS_MSEC_FRAC; + } + } + else if (!strncmp(fmt, "usec", 4)) { + fmt += 4; + if (!*fmt) { + fmt_type = TIME_FMT_ABS_USEC; + } + else if (!strcmp(fmt, "_frac")) { + fmt_type = TIME_FMT_ABS_USEC_FRAC; + } + } + else if (!strcmp(fmt, "sec")) { + fmt_type = TIME_FMT_ABS_SEC; + } + else if (!*fmt) { + fmt_type = TIME_FMT_CLF; + } + } + else { + fmt_type = TIME_FMT_CLF; + } + + if (fmt_type >= TIME_FMT_ABS_SEC) { /* Absolute (micro-/milli-)second time + * or msec/usec fraction + */ + char* buf = apr_palloc(r->pool, 20); + switch (fmt_type) { + case TIME_FMT_ABS_SEC: + apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_sec(request_time)); + break; + case TIME_FMT_ABS_MSEC: + apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_as_msec(request_time)); + break; + case TIME_FMT_ABS_USEC: + apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, request_time); + break; + case TIME_FMT_ABS_MSEC_FRAC: + apr_snprintf(buf, 20, "%03" APR_TIME_T_FMT, apr_time_msec(request_time)); + break; + case TIME_FMT_ABS_USEC_FRAC: + apr_snprintf(buf, 20, "%06" APR_TIME_T_FMT, apr_time_usec(request_time)); + break; + default: + return "-"; + } + return buf; + } + else if (fmt_type == TIME_FMT_CUSTOM) { /* Custom format */ + /* The custom time formatting uses a very large temp buffer + * on the stack. To avoid using so much stack space in the + * common case where we're not using a custom format, the code + * for the custom format in a separate function. (That's why + * log_request_time_custom is not inlined right here.) + */ + ap_explode_recent_localtime(&xt, request_time); + return log_request_time_custom(r, a, &xt); + } + else { /* CLF format */ + /* This code uses the same technique as ap_explode_recent_localtime(): + * optimistic caching with logic to detect and correct race conditions. + * See the comments in server/util_time.c for more information. + */ + cached_request_time* cached_time = apr_palloc(r->pool, + sizeof(*cached_time)); + unsigned t_seconds = (unsigned)apr_time_sec(request_time); + unsigned i = t_seconds & TIME_CACHE_MASK; + *cached_time = request_time_cache[i]; + if ((t_seconds != cached_time->t) || + (t_seconds != cached_time->t_validate)) { + + /* Invalid or old snapshot, so compute the proper time string + * and store it in the cache + */ + char sign; + int timz; + + ap_explode_recent_localtime(&xt, request_time); + timz = xt.tm_gmtoff; + if (timz < 0) { + timz = -timz; + sign = '-'; + } + else { + sign = '+'; + } + cached_time->t = t_seconds; + apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE, + "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]", + xt.tm_mday, apr_month_snames[xt.tm_mon], + xt.tm_year+1900, xt.tm_hour, xt.tm_min, xt.tm_sec, + sign, timz / (60*60), (timz % (60*60)) / 60); + cached_time->t_validate = t_seconds; + request_time_cache[i] = *cached_time; + } + return cached_time->timestr; + } +} + +static const char *log_request_duration_microseconds(request_rec *r, char *a) +{ + return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, + (get_request_end_time(r) - r->request_time)); +} + +static const char *log_request_duration_scaled(request_rec *r, char *a) +{ + apr_time_t duration = get_request_end_time(r) - r->request_time; + if (*a == '\0' || !strcasecmp(a, "s")) { + duration = apr_time_sec(duration); + } + else if (!strcasecmp(a, "ms")) { + duration = apr_time_as_msec(duration); + } + else if (!strcasecmp(a, "us")) { + } + else { + /* bogus format */ + return a; + } + return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, duration); +} + +/* These next two routines use the canonical name:port so that log + * parsers don't need to duplicate all the vhost parsing crud. + */ +static const char *log_virtual_host(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, r->server->server_hostname); +} + +static const char *log_server_port(request_rec *r, char *a) +{ + apr_port_t port; + + if (*a == '\0' || !strcasecmp(a, "canonical")) { + port = r->server->port ? r->server->port : ap_default_port(r); + } + else if (!strcasecmp(a, "remote")) { + port = r->useragent_addr->port; + } + else if (!strcasecmp(a, "local")) { + port = r->connection->local_addr->port; + } + else { + /* bogus format */ + return a; + } + return apr_itoa(r->pool, (int)port); +} + +/* This respects the setting of UseCanonicalName so that + * the dynamic mass virtual hosting trick works better. + */ +static const char *log_server_name(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, ap_get_server_name(r)); +} + +static const char *log_pid_tid(request_rec *r, char *a) +{ + if (*a == '\0' || !strcasecmp(a, "pid")) { + return ap_append_pid(r->pool, "", ""); + } + else if (!strcasecmp(a, "tid") || !strcasecmp(a, "hextid")) { +#if APR_HAS_THREADS + apr_os_thread_t tid = apr_os_thread_current(); +#else + int tid = 0; /* APR will format "0" anyway but an arg is needed */ +#endif + return apr_psprintf(r->pool, +#if APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 2) + /* APR can format a thread id in hex */ + *a == 'h' ? "%pt" : "%pT", +#else + /* APR is missing the feature, so always use decimal */ + "%pT", +#endif + &tid); + } + /* bogus format */ + return a; +} + +static const char *log_connection_status(request_rec *r, char *a) +{ + if (r->connection->aborted) + return "X"; + + if (r->connection->keepalive == AP_CONN_KEEPALIVE && + (!r->server->keep_alive_max || + (r->server->keep_alive_max - r->connection->keepalives) > 0)) { + return "+"; + } + return "-"; +} + +static const char *log_requests_on_connection(request_rec *r, char *a) +{ + int num = r->connection->keepalives ? r->connection->keepalives - 1 : 0; + return apr_itoa(r->pool, num); +} + +/***************************************************************** + * + * Parsing the log format string + */ + +static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it, + const char **sa) +{ + const char *s; + char *d; + + it->func = constant_item; + it->conditions = NULL; + + s = *sa; + while (*s && *s != '%') { + s++; + } + /* + * This might allocate a few chars extra if there's a backslash + * escape in the format string. + */ + it->arg = apr_palloc(p, s - *sa + 1); + + d = it->arg; + s = *sa; + while (*s && *s != '%') { + if (*s != '\\') { + *d++ = *s++; + } + else { + s++; + switch (*s) { + case '\\': + *d++ = '\\'; + s++; + break; + case 'r': + *d++ = '\r'; + s++; + break; + case 'n': + *d++ = '\n'; + s++; + break; + case 't': + *d++ = '\t'; + s++; + break; + default: + /* copy verbatim */ + *d++ = '\\'; + /* + * Allow the loop to deal with this *s in the normal + * fashion so that it handles end of string etc. + * properly. + */ + break; + } + } + } + *d = '\0'; + + *sa = s; + return NULL; +} + +static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa) +{ + const char *s = *sa; + ap_log_handler *handler = NULL; + + if (*s != '%') { + return parse_log_misc_string(p, it, sa); + } + + ++s; + it->condition_sense = 0; + it->conditions = NULL; + + if (*s == '%') { + it->arg = "%"; + it->func = constant_item; + *sa = ++s; + + return NULL; + } + + it->want_orig = -1; + it->arg = ""; /* For safety's sake... */ + + while (*s) { + int i; + + switch (*s) { + case '!': + ++s; + it->condition_sense = !it->condition_sense; + break; + + case '<': + ++s; + it->want_orig = 1; + break; + + case '>': + ++s; + it->want_orig = 0; + break; + + case ',': + ++s; + break; + + case '{': + ++s; + it->arg = ap_getword(p, &s, '}'); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i = *s - '0'; + while (apr_isdigit(*++s)) { + i = i * 10 + (*s) - '0'; + } + if (!it->conditions) { + it->conditions = apr_array_make(p, 4, sizeof(int)); + } + *(int *) apr_array_push(it->conditions) = i; + break; + + default: + /* check for '^' + two character format first */ + if (*s == '^' && *(s+1) && *(s+2)) { + handler = (ap_log_handler *)apr_hash_get(log_hash, s, 3); + if (handler) { + s += 3; + } + } + if (!handler) { + handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1); + } + if (!handler) { + char dummy[2]; + + dummy[0] = s[-1]; + dummy[1] = '\0'; + return apr_pstrcat(p, "Unrecognized LogFormat directive %", + dummy, NULL); + } + it->func = handler->func; + if (it->want_orig == -1) { + it->want_orig = handler->want_orig_default; + } + *sa = s; + return NULL; + } + } + + return "Ran off end of LogFormat parsing args to some directive"; +} + +static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err) +{ + apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item)); + char *res; + + while (*s) { + if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) { + *err = res; + return NULL; + } + } + + s = APR_EOL_STR; + parse_log_item(p, (log_format_item *) apr_array_push(a), &s); + return a; +} + +/***************************************************************** + * + * Actually logging. + */ + +static const char *process_item(request_rec *r, request_rec *orig, + log_format_item *item) +{ + const char *cp; + + /* First, see if we need to process this thing at all... */ + + if (item->conditions && item->conditions->nelts != 0) { + int i; + int *conds = (int *) item->conditions->elts; + int in_list = 0; + + for (i = 0; i < item->conditions->nelts; ++i) { + if (r->status == conds[i]) { + in_list = 1; + break; + } + } + + if ((item->condition_sense && in_list) + || (!item->condition_sense && !in_list)) { + return "-"; + } + } + + /* We do. Do it... */ + + cp = (*item->func) (item->want_orig ? orig : r, item->arg); + return cp ? cp : "-"; +} + +static void flush_log(buffered_log *buf) +{ + if (buf->outcnt && buf->handle != NULL) { + apr_file_write(buf->handle, buf->outbuf, &buf->outcnt); + buf->outcnt = 0; + } +} + + +static int config_log_transaction(request_rec *r, config_log_state *cls, + apr_array_header_t *default_format) +{ + log_format_item *items; + const char **strs; + int *strl; + request_rec *orig; + int i; + apr_size_t len = 0; + apr_array_header_t *format; + char *envar; + apr_status_t rv; + + if (cls->fname == NULL) { + return DECLINED; + } + + /* + * See if we've got any conditional envariable-controlled logging decisions + * to make. + */ + if (cls->condition_var != NULL) { + envar = cls->condition_var; + if (*envar != '!') { + if (apr_table_get(r->subprocess_env, envar) == NULL) { + return DECLINED; + } + } + else { + if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) { + return DECLINED; + } + } + } + else if (cls->condition_expr != NULL) { + const char *err; + int rc = ap_expr_exec(r, cls->condition_expr, &err); + if (rc < 0) + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00644) + "Error evaluating log condition: %s", err); + if (rc <= 0) + return DECLINED; + } + + format = cls->format ? cls->format : default_format; + + strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts)); + strl = apr_palloc(r->pool, sizeof(int) * (format->nelts)); + items = (log_format_item *) format->elts; + + orig = r; + while (orig->prev) { + orig = orig->prev; + } + while (r->next) { + r = r->next; + } + + for (i = 0; i < format->nelts; ++i) { + strs[i] = process_item(r, orig, &items[i]); + } + + for (i = 0; i < format->nelts; ++i) { + len += strl[i] = strlen(strs[i]); + } + if (!log_writer) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00645) + "log writer isn't correctly setup"); + return HTTP_INTERNAL_SERVER_ERROR; + } + rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646) + "Error writing to %s", cls->fname); + } + return OK; +} + +static int multi_log_transaction(request_rec *r) +{ + multi_log_state *mls = ap_get_module_config(r->server->module_config, + &log_config_module); + config_log_state *clsarray; + int i; + + /* + * Initialize per request state + */ + log_request_state *state = apr_pcalloc(r->pool, sizeof(log_request_state)); + ap_set_module_config(r->request_config, &log_config_module, state); + + /* + * Log this transaction.. + */ + if (mls->config_logs->nelts) { + clsarray = (config_log_state *) mls->config_logs->elts; + for (i = 0; i < mls->config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + config_log_transaction(r, cls, mls->default_format); + } + } + + if (mls->server_config_logs) { + clsarray = (config_log_state *) mls->server_config_logs->elts; + for (i = 0; i < mls->server_config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + if (cls->inherit || !mls->config_logs->nelts) { + config_log_transaction(r, cls, mls->default_format); + } + } + } + + return OK; +} + +/***************************************************************** + * + * Module glue... + */ + +static void *make_config_log_state(apr_pool_t *p, server_rec *s) +{ + multi_log_state *mls; + + mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state)); + mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state)); + mls->default_format_string = NULL; + mls->default_format = NULL; + mls->server_config_logs = NULL; + mls->formats = apr_table_make(p, 4); + apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT); + + return mls; +} + +/* + * Use the merger to simply add a pointer from the vhost log state + * to the log of logs specified for the non-vhost configuration. Make sure + * vhosts inherit any globally-defined format names. + */ + +static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv) +{ + multi_log_state *base = (multi_log_state *) basev; + multi_log_state *add = (multi_log_state *) addv; + + add->server_config_logs = base->config_logs; + if (!add->default_format) { + add->default_format_string = base->default_format_string; + add->default_format = base->default_format; + } + add->formats = apr_table_overlay(p, base->formats, add->formats); + + return add; +} + +/* + * Set the default logfile format, or define a nickname for a format string. + */ +static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt, + const char *name) +{ + const char *err_string = NULL; + multi_log_state *mls = ap_get_module_config(cmd->server->module_config, + &log_config_module); + + /* + * If we were given two arguments, the second is a name to be given to the + * format. This syntax just defines the nickname - it doesn't actually + * make the format the default. + */ + if (name != NULL) { + parse_log_string(cmd->pool, fmt, &err_string); + if (err_string == NULL) { + apr_table_setn(mls->formats, name, fmt); + } + } + else { + mls->default_format_string = fmt; + mls->default_format = parse_log_string(cmd->pool, fmt, &err_string); + } + return err_string; +} + + +static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn, + const char *fmt, const char *envclause) +{ + const char *err_string = NULL; + multi_log_state *mls = ap_get_module_config(cmd->server->module_config, + &log_config_module); + config_log_state *cls; + + cls = (config_log_state *) apr_array_push(mls->config_logs); + cls->condition_var = NULL; + cls->condition_expr = NULL; + if (envclause != NULL) { + if (strncasecmp(envclause, "env=", 4) == 0) { + if ((envclause[4] == '\0') + || ((envclause[4] == '!') && (envclause[5] == '\0'))) { + return "missing environment variable name"; + } + cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]); + } + else if (strncasecmp(envclause, "expr=", 5) == 0) { + const char *err; + if ((envclause[5] == '\0')) + return "missing condition"; + cls->condition_expr = ap_expr_parse_cmd(cmd, &envclause[5], + AP_EXPR_FLAG_DONT_VARY, + &err, NULL); + if (err) + return err; + } + else { + return "error in condition clause"; + } + } + + cls->fname = fn; + cls->format_string = fmt; + cls->directive = cmd->directive; + if (fmt == NULL) { + cls->format = NULL; + } + else { + cls->format = parse_log_string(cmd->pool, fmt, &err_string); + } + cls->log_writer = NULL; + + return err_string; +} + +static const char *add_global_log(cmd_parms *cmd, void *dummy, const char *fn, + const char *fmt, const char *envclause) { + multi_log_state *mls = ap_get_module_config(cmd->server->module_config, + &log_config_module); + config_log_state *clsarray; + config_log_state *cls; + const char *ret; + + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + + if (err) { + return err; + } + + /* Add a custom log through the normal channel */ + ret = add_custom_log(cmd, dummy, fn, fmt, envclause); + + /* Set the inherit flag unless there was some error */ + if (ret == NULL) { + clsarray = (config_log_state*)mls->config_logs->elts; + cls = &clsarray[mls->config_logs->nelts-1]; + cls->inherit = 1; + } + + return ret; +} + +static const char *set_transfer_log(cmd_parms *cmd, void *dummy, + const char *fn) +{ + return add_custom_log(cmd, dummy, fn, NULL, NULL); +} + +static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag) +{ + buffered_logs = flag; + if (buffered_logs) { + ap_log_set_writer_init(ap_buffered_log_writer_init); + ap_log_set_writer(ap_buffered_log_writer); + } + else { + ap_log_set_writer_init(ap_default_log_writer_init); + ap_log_set_writer(ap_default_log_writer); + } + return NULL; +} +static const command_rec config_log_cmds[] = +{ +AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF, + "a file name, a custom log format string or format name, " + "and an optional \"env=\" or \"expr=\" clause (see docs)"), +AP_INIT_TAKE23("GlobalLog", add_global_log, NULL, RSRC_CONF, + "Same as CustomLog, but forces virtualhosts to inherit the log"), +AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF, + "the filename of the access log"), +AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF, + "a log format string (see docs) and an optional format name"), +AP_INIT_FLAG("BufferedLogs", set_buffered_logs_on, NULL, RSRC_CONF, + "Enable Buffered Logging (experimental)"), + {NULL} +}; + +static config_log_state *open_config_log(server_rec *s, apr_pool_t *p, + config_log_state *cls, + apr_array_header_t *default_format) +{ + if (cls->log_writer != NULL) { + return cls; /* virtual config shared w/main server */ + } + + if (cls->fname == NULL) { + return cls; /* Leave it NULL to decline. */ + } + + cls->log_writer = log_writer_init(p, s, cls->fname); + if (cls->log_writer == NULL) + return NULL; + + return cls; +} + +static int open_multi_logs(server_rec *s, apr_pool_t *p) +{ + int i; + multi_log_state *mls = ap_get_module_config(s->module_config, + &log_config_module); + config_log_state *clsarray; + const char *dummy; + const char *format; + + if (mls->default_format_string) { + format = apr_table_get(mls->formats, mls->default_format_string); + if (format) { + mls->default_format = parse_log_string(p, format, &dummy); + } + } + + if (!mls->default_format) { + mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy); + } + + if (mls->config_logs->nelts) { + clsarray = (config_log_state *) mls->config_logs->elts; + for (i = 0; i < mls->config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + if (cls->format_string) { + format = apr_table_get(mls->formats, cls->format_string); + if (format) { + cls->format = parse_log_string(p, format, &dummy); + } + } + + if (!open_config_log(s, p, cls, mls->default_format)) { + /* Failure already logged by open_config_log */ + return DONE; + } + } + } + else if (mls->server_config_logs) { + clsarray = (config_log_state *) mls->server_config_logs->elts; + for (i = 0; i < mls->server_config_logs->nelts; ++i) { + config_log_state *cls = &clsarray[i]; + + if (cls->format_string) { + format = apr_table_get(mls->formats, cls->format_string); + if (format) { + cls->format = parse_log_string(p, format, &dummy); + } + } + + if (!open_config_log(s, p, cls, mls->default_format)) { + /* Failure already logged by open_config_log */ + return DONE; + } + } + } + + return OK; +} + + +static apr_status_t flush_all_logs(void *data) +{ + server_rec *s = data; + multi_log_state *mls; + apr_array_header_t *log_list; + config_log_state *clsarray; + buffered_log *buf; + int i; + + if (!buffered_logs) + return APR_SUCCESS; + + for (; s; s = s->next) { + mls = ap_get_module_config(s->module_config, &log_config_module); + log_list = NULL; + if (mls->config_logs->nelts) { + log_list = mls->config_logs; + } + else if (mls->server_config_logs) { + log_list = mls->server_config_logs; + } + if (log_list) { + clsarray = (config_log_state *) log_list->elts; + for (i = 0; i < log_list->nelts; ++i) { + buf = clsarray[i].log_writer; + flush_log(buf); + } + } + } + return APR_SUCCESS; +} + + +static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s) +{ + int res; + + /* First init the buffered logs array, which is needed when opening the logs. */ + if (buffered_logs) { + all_buffered_logs = apr_array_make(p, 5, sizeof(buffered_log *)); + } + + /* Next, do "physical" server, which gets default log fd and format + * for the virtual servers, if they don't override... + */ + res = open_multi_logs(s, p); + + /* Then, virtual servers */ + + for (s = s->next; (res == OK) && s; s = s->next) { + res = open_multi_logs(s, p); + } + + return res; +} + +static void init_child(apr_pool_t *p, server_rec *s) +{ + int mpm_threads; + + ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads); + + /* Now register the last buffer flush with the cleanup engine */ + if (buffered_logs) { + int i; + buffered_log **array = (buffered_log **)all_buffered_logs->elts; + + apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs); + + for (i = 0; i < all_buffered_logs->nelts; i++) { + buffered_log *this = array[i]; + +#if APR_HAS_THREADS + if (mpm_threads > 1) { + apr_status_t rv; + + this->mutex.type = apr_anylock_threadmutex; + rv = apr_thread_mutex_create(&this->mutex.lock.tm, + APR_THREAD_MUTEX_DEFAULT, + p); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00647) + "could not initialize buffered log mutex, " + "transfer log may become corrupted"); + this->mutex.type = apr_anylock_none; + } + } + else +#endif + { + this->mutex.type = apr_anylock_none; + } + } + } +} + +static void ap_register_log_handler(apr_pool_t *p, char *tag, + ap_log_handler_fn_t *handler, int def) +{ + ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct)); + log_struct->func = handler; + log_struct->want_orig_default = def; + + apr_hash_set(log_hash, tag, strlen(tag), (const void *)log_struct); +} +static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle) +{ + ap_log_writer_init *old = log_writer_init; + log_writer_init = handle; + + return old; + +} +static ap_log_writer *ap_log_set_writer(ap_log_writer *handle) +{ + ap_log_writer *old = log_writer; + log_writer = handle; + + return old; +} + +static apr_status_t ap_default_log_writer( request_rec *r, + void *handle, + const char **strs, + int *strl, + int nelts, + apr_size_t len) + +{ + char *str; + char *s; + int i; + apr_status_t rv; + + /* + * We do this memcpy dance because write() is atomic for len < PIPE_BUF, + * while writev() need not be. + */ + str = apr_palloc(r->pool, len + 1); + + for (i = 0, s = str; i < nelts; ++i) { + memcpy(s, strs[i], strl[i]); + s += strl[i]; + } + + rv = apr_file_write((apr_file_t*)handle, str, &len); + + return rv; +} +static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name) +{ + if (*name == '|') { + piped_log *pl; + + pl = ap_open_piped_log(p, name + 1); + if (pl == NULL) { + return NULL; + } + return ap_piped_log_write_fd(pl); + } + else { + const char *fname = ap_server_root_relative(p, name); + apr_file_t *fd; + apr_status_t rv; + + if (!fname) { + ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, APLOGNO(00648) + "invalid transfer log path %s.", name); + return NULL; + } + rv = apr_file_open(&fd, fname, xfer_flags, xfer_perms, p); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00649) + "could not open transfer log file %s.", fname); + return NULL; + } + return fd; + } +} +static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name) +{ + buffered_log *b; + b = apr_pcalloc(p, sizeof(buffered_log)); + b->handle = ap_default_log_writer_init(p, s, name); + + if (b->handle) { + *(buffered_log **)apr_array_push(all_buffered_logs) = b; + return b; + } + else + return NULL; +} +static apr_status_t ap_buffered_log_writer(request_rec *r, + void *handle, + const char **strs, + int *strl, + int nelts, + apr_size_t len) + +{ + char *str; + char *s; + int i; + apr_status_t rv; + buffered_log *buf = (buffered_log*)handle; + + if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) { + return rv; + } + + if (len + buf->outcnt > LOG_BUFSIZE) { + flush_log(buf); + } + if (len >= LOG_BUFSIZE) { + apr_size_t w; + + /* + * We do this memcpy dance because write() is atomic for + * len < PIPE_BUF, while writev() need not be. + */ + str = apr_palloc(r->pool, len + 1); + for (i = 0, s = str; i < nelts; ++i) { + memcpy(s, strs[i], strl[i]); + s += strl[i]; + } + w = len; + rv = apr_file_write(buf->handle, str, &w); + + } + else { + for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) { + memcpy(s, strs[i], strl[i]); + s += strl[i]; + } + buf->outcnt += len; + rv = APR_SUCCESS; + } + + APR_ANYLOCK_UNLOCK(&buf->mutex); + return rv; +} + +static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) +{ + static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; + + log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); + + if (log_pfn_register) { + log_pfn_register(p, "h", log_remote_host, 0); + log_pfn_register(p, "a", log_remote_address, 0 ); + log_pfn_register(p, "A", log_local_address, 0 ); + log_pfn_register(p, "l", log_remote_logname, 0); + log_pfn_register(p, "u", log_remote_user, 0); + log_pfn_register(p, "t", log_request_time, 0); + log_pfn_register(p, "f", log_request_file, 0); + log_pfn_register(p, "b", clf_log_bytes_sent, 0); + log_pfn_register(p, "B", log_bytes_sent, 0); + log_pfn_register(p, "i", log_header_in, 0); + log_pfn_register(p, "o", log_header_out, 0); + log_pfn_register(p, "n", log_note, 0); + log_pfn_register(p, "L", log_log_id, 1); + log_pfn_register(p, "e", log_env_var, 0); + log_pfn_register(p, "V", log_server_name, 0); + log_pfn_register(p, "v", log_virtual_host, 0); + log_pfn_register(p, "p", log_server_port, 0); + log_pfn_register(p, "P", log_pid_tid, 0); + log_pfn_register(p, "H", log_request_protocol, 0); + log_pfn_register(p, "m", log_request_method, 0); + log_pfn_register(p, "q", log_request_query, 0); + log_pfn_register(p, "X", log_connection_status, 0); + log_pfn_register(p, "C", log_cookie, 0); + log_pfn_register(p, "k", log_requests_on_connection, 0); + log_pfn_register(p, "r", log_request_line, 1); + log_pfn_register(p, "D", log_request_duration_microseconds, 1); + log_pfn_register(p, "T", log_request_duration_scaled, 1); + log_pfn_register(p, "U", log_request_uri, 1); + log_pfn_register(p, "s", log_status, 1); + log_pfn_register(p, "R", log_handler, 1); + + log_pfn_register(p, "^ti", log_trailer_in, 0); + log_pfn_register(p, "^to", log_trailer_out, 0); + } + + /* reset to default conditions */ + ap_log_set_writer_init(ap_default_log_writer_init); + ap_log_set_writer(ap_default_log_writer); + buffered_logs = 0; + + return OK; +} + +static int check_log_dir(apr_pool_t *p, server_rec *s, config_log_state *cls) +{ + if (!cls->fname || cls->fname[0] == '|' || !cls->directive) { + return OK; + } + else { + char *abs = ap_server_root_relative(p, cls->fname); + char *dir = ap_make_dirstr_parent(p, abs); + apr_finfo_t finfo; + const ap_directive_t *directive = cls->directive; + apr_status_t rv = apr_stat(&finfo, dir, APR_FINFO_TYPE, p); + cls->directive = NULL; /* Don't check this config_log_state again */ + if (rv == APR_SUCCESS && finfo.filetype != APR_DIR) + rv = APR_ENOTDIR; + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, rv, s, + APLOGNO(02297) + "Cannot access directory '%s' for log file '%s' " + "defined at %s:%d", dir, cls->fname, + directive->filename, directive->line_num); + return !OK; + } + } + return OK; +} + +static int log_check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +{ + int rv = OK; + while (s) { + multi_log_state *mls = ap_get_module_config(s->module_config, + &log_config_module); + /* + * We don't need to check mls->server_config_logs because it just + * points to the parent server's mls->config_logs. + */ + apr_array_header_t *log_list = mls->config_logs; + config_log_state *clsarray = (config_log_state *) log_list->elts; + int i; + for (i = 0; i < log_list->nelts; ++i) { + if (check_log_dir(ptemp, s, &clsarray[i]) != OK) + rv = !OK; + } + + s = s->next; + } + return rv; +} + +static void register_hooks(apr_pool_t *p) +{ + ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST); + ap_hook_check_config(log_check_config,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE); + + /* Init log_hash before we register the optional function. It is + * possible for the optional function, ap_register_log_handler, + * to be called before any other mod_log_config hooks are called. + * As a policy, we should init everything required by an optional function + * before calling APR_REGISTER_OPTIONAL_FN. + */ + log_hash = apr_hash_make(p); + APR_REGISTER_OPTIONAL_FN(ap_register_log_handler); + APR_REGISTER_OPTIONAL_FN(ap_log_set_writer_init); + APR_REGISTER_OPTIONAL_FN(ap_log_set_writer); +} + +AP_DECLARE_MODULE(log_config) = +{ + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config */ + NULL, /* merge per-dir config */ + make_config_log_state, /* server config */ + merge_config_log_state, /* merge server config */ + config_log_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; + diff --git a/modules/loggers/mod_log_config.dep b/modules/loggers/mod_log_config.dep new file mode 100644 index 0000000..8107bd9 --- /dev/null +++ b/modules/loggers/mod_log_config.dep @@ -0,0 +1,62 @@ +# Microsoft Developer Studio Generated Dependency File, included by mod_log_config.mak + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + + +.\mod_log_config.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_protocol.h"\ + "..\..\include\httpd.h"\ + "..\..\include\os.h"\ + "..\..\include\scoreboard.h"\ + "..\..\include\util_cfgtree.h"\ + "..\..\include\util_filter.h"\ + "..\..\include\util_time.h"\ + "..\..\srclib\apr-util\include\apr_anylock.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_thread_rwlock.h"\ + "..\..\srclib\apr\include\apr_time.h"\ + "..\..\srclib\apr\include\apr_user.h"\ + "..\..\srclib\apr\include\apr_want.h"\ + ".\mod_log_config.h"\ + diff --git a/modules/loggers/mod_log_config.dsp b/modules/loggers/mod_log_config.dsp new file mode 100644 index 0000000..2338875 --- /dev/null +++ b/modules/loggers/mod_log_config.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="mod_log_config" - 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_log_config - 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_log_config.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_log_config.mak" CFG="mod_log_config - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_log_config - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_log_config - 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_log_config - 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_log_config_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_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_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_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_log_config.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_log_config - 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_log_config_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_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_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_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_log_config.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_log_config - Win32 Release" +# Name "mod_log_config - Win32 Debug" +# Begin Source File + +SOURCE=.\mod_log_config.c +# End Source File +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/loggers/mod_log_config.exp b/modules/loggers/mod_log_config.exp new file mode 100644 index 0000000..0749e52 --- /dev/null +++ b/modules/loggers/mod_log_config.exp @@ -0,0 +1 @@ +log_config_module diff --git a/modules/loggers/mod_log_config.h b/modules/loggers/mod_log_config.h new file mode 100644 index 0000000..877a593 --- /dev/null +++ b/modules/loggers/mod_log_config.h @@ -0,0 +1,74 @@ +/* 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_log_config.h + * @brief Logging Configuration Extension Module for Apache + * + * @defgroup MOD_LOG_CONFIG mod_log_config + * @ingroup APACHE_MODS + * @{ + */ + +#include "apr_optional.h" +#include "httpd.h" +#include "scoreboard.h" + +#ifndef _MOD_LOG_CONFIG_H +#define _MOD_LOG_CONFIG_H 1 + +/** + * callback function prototype for a external log handler + */ +typedef const char *ap_log_handler_fn_t(request_rec *r, char *a); + +/** + * callback function prototype for external writer initialization. + */ +typedef void *ap_log_writer_init(apr_pool_t *p, server_rec *s, + const char *name); +/** + * callback which gets called where there is a log line to write. + */ +typedef apr_status_t ap_log_writer( + request_rec *r, + void *handle, + const char **portions, + int *lengths, + int nelts, + apr_size_t len); + +typedef struct ap_log_handler { + ap_log_handler_fn_t *func; + int want_orig_default; +} ap_log_handler; + +APR_DECLARE_OPTIONAL_FN(void, ap_register_log_handler, + (apr_pool_t *p, char *tag, ap_log_handler_fn_t *func, + int def)); +/** + * you will need to set your init handler *BEFORE* the open_logs + * in mod_log_config gets executed + */ +APR_DECLARE_OPTIONAL_FN(ap_log_writer_init*, ap_log_set_writer_init,(ap_log_writer_init *func)); +/** + * you should probably set the writer at the same time (ie..before open_logs) + */ +APR_DECLARE_OPTIONAL_FN(ap_log_writer*, ap_log_set_writer, (ap_log_writer* func)); + +#endif /* MOD_LOG_CONFIG */ +/** @} */ + diff --git a/modules/loggers/mod_log_config.mak b/modules/loggers/mod_log_config.mak new file mode 100644 index 0000000..df9ddf6 --- /dev/null +++ b/modules/loggers/mod_log_config.mak @@ -0,0 +1,353 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on mod_log_config.dsp +!IF "$(CFG)" == "" +CFG=mod_log_config - Win32 Release +!MESSAGE No configuration specified. Defaulting to mod_log_config - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "mod_log_config - Win32 Release" && "$(CFG)" != "mod_log_config - 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_log_config.mak" CFG="mod_log_config - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_log_config - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_log_config - 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_log_config - 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_log_config.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_log_config.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_log_config.obj" + -@erase "$(INTDIR)\mod_log_config.res" + -@erase "$(INTDIR)\mod_log_config_src.idb" + -@erase "$(INTDIR)\mod_log_config_src.pdb" + -@erase "$(OUTDIR)\mod_log_config.exp" + -@erase "$(OUTDIR)\mod_log_config.lib" + -@erase "$(OUTDIR)\mod_log_config.pdb" + -@erase "$(OUTDIR)\mod_log_config.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_log_config_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_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_config.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_config.pdb" /debug /out:"$(OUTDIR)\mod_log_config.so" /implib:"$(OUTDIR)\mod_log_config.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\mod_log_config.obj" \ + "$(INTDIR)\mod_log_config.res" \ + "..\..\srclib\apr\Release\libapr-1.lib" \ + "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ + "..\..\Release\libhttpd.lib" + +"$(OUTDIR)\mod_log_config.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\mod_log_config.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_log_config.so" + if exist .\Release\mod_log_config.so.manifest mt.exe -manifest .\Release\mod_log_config.so.manifest -outputresource:.\Release\mod_log_config.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "mod_log_config - 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_log_config.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_log_config.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_log_config.obj" + -@erase "$(INTDIR)\mod_log_config.res" + -@erase "$(INTDIR)\mod_log_config_src.idb" + -@erase "$(INTDIR)\mod_log_config_src.pdb" + -@erase "$(OUTDIR)\mod_log_config.exp" + -@erase "$(OUTDIR)\mod_log_config.lib" + -@erase "$(OUTDIR)\mod_log_config.pdb" + -@erase "$(OUTDIR)\mod_log_config.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_log_config_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_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_config.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_config.pdb" /debug /out:"$(OUTDIR)\mod_log_config.so" /implib:"$(OUTDIR)\mod_log_config.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so +LINK32_OBJS= \ + "$(INTDIR)\mod_log_config.obj" \ + "$(INTDIR)\mod_log_config.res" \ + "..\..\srclib\apr\Debug\libapr-1.lib" \ + "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ + "..\..\Debug\libhttpd.lib" + +"$(OUTDIR)\mod_log_config.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\mod_log_config.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_log_config.so" + if exist .\Debug\mod_log_config.so.manifest mt.exe -manifest .\Debug\mod_log_config.so.manifest -outputresource:.\Debug\mod_log_config.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("mod_log_config.dep") +!INCLUDE "mod_log_config.dep" +!ELSE +!MESSAGE Warning: cannot find "mod_log_config.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "mod_log_config - Win32 Release" || "$(CFG)" == "mod_log_config - Win32 Debug" + +!IF "$(CFG)" == "mod_log_config - Win32 Release" + +"libapr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" + cd "..\..\modules\loggers" + +"libapr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug" + +"libapr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" + cd "..\..\modules\loggers" + +"libapr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_log_config - Win32 Release" + +"libaprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" + cd "..\..\modules\loggers" + +"libaprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug" + +"libaprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" + cd "..\..\modules\loggers" + +"libaprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_log_config - Win32 Release" + +"libhttpd - Win32 Release" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" + cd ".\modules\loggers" + +"libhttpd - Win32 ReleaseCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug" + +"libhttpd - Win32 Debug" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" + cd ".\modules\loggers" + +"libhttpd - Win32 DebugCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "mod_log_config - Win32 Release" + + +"$(INTDIR)\mod_log_config.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache" $(SOURCE) + + +!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug" + + +"$(INTDIR)\mod_log_config.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache" $(SOURCE) + + +!ENDIF + +SOURCE=.\mod_log_config.c + +"$(INTDIR)\mod_log_config.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/modules/loggers/mod_log_debug.c b/modules/loggers/mod_log_debug.c new file mode 100644 index 0000000..8a6c124 --- /dev/null +++ b/modules/loggers/mod_log_debug.c @@ -0,0 +1,287 @@ +/* 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 "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_request.h" +#include "ap_expr.h" + +extern module AP_MODULE_DECLARE_DATA log_debug_module; + +typedef struct { + ap_expr_info_t *msg_expr; + ap_expr_info_t *condition; + const char *hook; +} msg_entry; + +typedef struct { + apr_array_header_t *entries; +} log_debug_dirconf; + +static const char *allhooks = "all"; +static const char * const hooks[] = { + "log_transaction", /* 0 */ + "quick_handler", /* 1 */ + "handler", /* 2 */ + "translate_name", /* 3 */ + "map_to_storage", /* 4 */ + "fixups", /* 5 */ + "type_checker", /* 6 */ + "check_access", /* 7 */ + "check_access_ex", /* 8 */ + "check_authn", /* 9 */ + "check_authz", /* 10 */ + "insert_filter", /* 11 */ + NULL +}; + +static void do_debug_log(request_rec *r, const char *hookname) +{ + log_debug_dirconf *dconf = ap_get_module_config(r->per_dir_config, &log_debug_module); + int i; + if (dconf->entries == NULL) + return; + + for (i = 0; i < dconf->entries->nelts; i++) { + const char *msg, *err; + msg_entry *entry = APR_ARRAY_IDX(dconf->entries, i, msg_entry *); + if (entry->hook != allhooks && entry->hook != hookname) + continue; + if (entry->condition) { + int ret = ap_expr_exec(r, entry->condition, &err); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00640) + "Can't evaluate condition: %s", err); + continue; + } + if (!ret) + continue; + } + msg = ap_expr_str_exec(r, entry->msg_expr, &err); + if (err) + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00641) + "Can't evaluate message expression: %s", err); + if (APLOGrdebug(r)) + /* Intentional no APLOGNO */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "%s (%s hook, %s:%d)", + msg, hookname, entry->msg_expr->filename, + entry->msg_expr->line_number); + else + /* Intentional no APLOGNO */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "%s", msg); + } +} + +static int log_debug_log_transaction(request_rec *r) +{ + do_debug_log(r, hooks[0]); + return DECLINED; +} + +static int log_debug_quick_handler(request_rec *r, int lookup_uri) +{ + do_debug_log(r, hooks[1]); + return DECLINED; +} + +static int log_debug_handler(request_rec *r) +{ + do_debug_log(r, hooks[2]); + return DECLINED; +} + +static int log_debug_translate_name(request_rec *r) +{ + do_debug_log(r, hooks[3]); + return DECLINED; +} + +static int log_debug_map_to_storage(request_rec *r) +{ + do_debug_log(r, hooks[4]); + return DECLINED; +} + +static int log_debug_fixups(request_rec *r) +{ + do_debug_log(r, hooks[5]); + return DECLINED; +} + +static int log_debug_type_checker(request_rec *r) +{ + do_debug_log(r, hooks[6]); + return DECLINED; +} + +static int log_debug_check_access(request_rec *r) +{ + do_debug_log(r, hooks[7]); + return DECLINED; +} + +static int log_debug_check_access_ex(request_rec *r) +{ + do_debug_log(r, hooks[8]); + return DECLINED; +} + +static int log_debug_check_authn(request_rec *r) +{ + do_debug_log(r, hooks[9]); + return DECLINED; +} + +static int log_debug_check_authz(request_rec *r) +{ + do_debug_log(r, hooks[10]); + return DECLINED; +} + +static void log_debug_insert_filter(request_rec *r) +{ + do_debug_log(r, hooks[11]); +} + +static void *log_debug_create_dconf(apr_pool_t *p, char *dirspec) +{ + log_debug_dirconf *dconf = apr_pcalloc(p, sizeof(log_debug_dirconf)); + return dconf; +} + +static void *log_debug_merge_dconf(apr_pool_t *p, void *parent_conf, void *new_conf) +{ + log_debug_dirconf *merged = apr_pcalloc(p, sizeof(log_debug_dirconf)); + const log_debug_dirconf *parent = parent_conf; + const log_debug_dirconf *new = new_conf; + + if (parent->entries == NULL) + merged->entries = new->entries; + else if (new->entries == NULL) + merged->entries = parent->entries; + else + /* apr_array_append actually creates a new array */ + merged->entries = apr_array_append(p, parent->entries, new->entries); + + return merged; +} + +static const char *cmd_log_message(cmd_parms *cmd, void *dconf_, const char *arg1, + const char *arg2, const char *arg3) +{ + msg_entry *entry = apr_pcalloc(cmd->pool, sizeof(msg_entry)); + log_debug_dirconf *dconf = dconf_; + int i, j; + const char *err; + const char *args[2]; + args[0] = arg2; + args[1] = arg3; + + entry->msg_expr = ap_expr_parse_cmd(cmd, arg1, AP_EXPR_FLAG_STRING_RESULT| + AP_EXPR_FLAG_DONT_VARY, + &err, NULL); + if (err) + return apr_psprintf(cmd->pool, + "Could not parse message expression '%s': %s", + arg1, err); + + for (i = 0; i < 2; i++) { + if (args[i] == NULL) + break; + + if (strncasecmp(args[i], "hook=", 5) == 0) { + const char *name = args[i] + 5; + j = 0; + while (hooks[j]) { + if (strcasecmp(hooks[j], name) == 0) { + entry->hook = hooks[j]; + break; + } + j++; + } + if (entry->hook == NULL) { + if (strcmp(name, "*") == 0 || strcasecmp(name, allhooks) == 0) + entry->hook = allhooks; + else + return apr_psprintf(cmd->pool, "Invalid hook name: %s", name); + } + } + else if (strncasecmp(args[i], "expr=", 5) == 0) { + const char *expr = args[i] + 5; + entry->condition = ap_expr_parse_cmd(cmd, expr, + AP_EXPR_FLAG_DONT_VARY, + &err, NULL); + if (err) + return apr_psprintf(cmd->pool, + "Could not parse expression '%s': %s", + expr, err); + } + else { + return apr_psprintf(cmd->pool, "Invalid argument %s", args[i]); + } + } + if (entry->hook == NULL) + entry->hook = hooks[0]; + + if (!dconf->entries) + dconf->entries = apr_array_make(cmd->pool, 4, sizeof(msg_entry *)); + + APR_ARRAY_PUSH(dconf->entries, msg_entry *) = entry; + + return NULL; +} + +static const command_rec log_debug_cmds[] = +{ + AP_INIT_TAKE123("LogMessage", cmd_log_message, NULL, RSRC_CONF|ACCESS_CONF, + "Log a debug message to the error log if this config block is used for " + " a request"), + {NULL} +}; + +static void register_hooks(apr_pool_t *p) +{ + ap_hook_log_transaction(log_debug_log_transaction, NULL, NULL, APR_HOOK_FIRST); + ap_hook_quick_handler(log_debug_quick_handler, NULL, NULL, APR_HOOK_FIRST); + ap_hook_handler(log_debug_handler, NULL, NULL, APR_HOOK_FIRST); + ap_hook_translate_name(log_debug_translate_name, NULL, NULL, APR_HOOK_FIRST); + ap_hook_map_to_storage(log_debug_map_to_storage, NULL, NULL, APR_HOOK_FIRST); + ap_hook_fixups(log_debug_fixups, NULL, NULL, APR_HOOK_FIRST); + ap_hook_type_checker(log_debug_type_checker, NULL, NULL, APR_HOOK_FIRST); + ap_hook_check_access(log_debug_check_access, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI); + ap_hook_check_access_ex(log_debug_check_access_ex, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI); + ap_hook_check_authn(log_debug_check_authn, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI); + ap_hook_check_authz(log_debug_check_authz, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI); + ap_hook_insert_filter(log_debug_insert_filter, NULL, NULL, APR_HOOK_FIRST); +} + +AP_DECLARE_MODULE(log_debug) = +{ + STANDARD20_MODULE_STUFF, + log_debug_create_dconf, /* create per-dir config */ + log_debug_merge_dconf, /* merge per-dir config */ + NULL, /* server config */ + NULL, /* merge server config */ + log_debug_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; + diff --git a/modules/loggers/mod_log_debug.dep b/modules/loggers/mod_log_debug.dep new file mode 100644 index 0000000..eed5a6d --- /dev/null +++ b/modules/loggers/mod_log_debug.dep @@ -0,0 +1,54 @@ +# Microsoft Developer Studio Generated Dependency File, included by mod_log_debug.mak + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + + +.\mod_log_debug.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_log.h"\ + "..\..\include\http_protocol.h"\ + "..\..\include\http_request.h"\ + "..\..\include\httpd.h"\ + "..\..\include\os.h"\ + "..\..\include\util_cfgtree.h"\ + "..\..\include\util_filter.h"\ + "..\..\srclib\apr-util\include\apr_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/loggers/mod_log_debug.dsp b/modules/loggers/mod_log_debug.dsp new file mode 100644 index 0000000..f96e2ae --- /dev/null +++ b/modules/loggers/mod_log_debug.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="mod_log_debug" - 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_log_debug - 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_log_debug.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_log_debug.mak" CFG="mod_log_debug - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_log_debug - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_log_debug - 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_log_debug - 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_log_debug_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_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_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_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_log_debug.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_log_debug - 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_log_debug_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_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_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_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_log_debug.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_log_debug - Win32 Release" +# Name "mod_log_debug - Win32 Debug" +# Begin Source File + +SOURCE=.\mod_log_debug.c +# End Source File +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/loggers/mod_log_debug.mak b/modules/loggers/mod_log_debug.mak new file mode 100644 index 0000000..94b0bee --- /dev/null +++ b/modules/loggers/mod_log_debug.mak @@ -0,0 +1,325 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on mod_log_debug.dsp +!IF "$(CFG)" == "" +CFG=mod_log_debug - Win32 Release +!MESSAGE No configuration specified. Defaulting to mod_log_debug - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "mod_log_debug - Win32 Release" && "$(CFG)" != "mod_log_debug - 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_log_debug.mak" CFG="mod_log_debug - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_log_debug - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_log_debug - 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_log_debug - 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_log_debug.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_log_debug.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_log_debug.obj" + -@erase "$(INTDIR)\mod_log_debug.res" + -@erase "$(INTDIR)\mod_log_debug_src.idb" + -@erase "$(INTDIR)\mod_log_debug_src.pdb" + -@erase "$(OUTDIR)\mod_log_debug.exp" + -@erase "$(OUTDIR)\mod_log_debug.lib" + -@erase "$(OUTDIR)\mod_log_debug.pdb" + -@erase "$(OUTDIR)\mod_log_debug.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_log_debug_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_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_debug.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_debug.pdb" /debug /out:"$(OUTDIR)\mod_log_debug.so" /implib:"$(OUTDIR)\mod_log_debug.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\mod_log_debug.obj" \ + "$(INTDIR)\mod_log_debug.res" \ + "..\..\srclib\apr\Release\libapr-1.lib" \ + "..\..\Release\libhttpd.lib" + +"$(OUTDIR)\mod_log_debug.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\mod_log_debug.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_log_debug.so" + if exist .\Release\mod_log_debug.so.manifest mt.exe -manifest .\Release\mod_log_debug.so.manifest -outputresource:.\Release\mod_log_debug.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "mod_log_debug - 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_log_debug.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_log_debug.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_log_debug.obj" + -@erase "$(INTDIR)\mod_log_debug.res" + -@erase "$(INTDIR)\mod_log_debug_src.idb" + -@erase "$(INTDIR)\mod_log_debug_src.pdb" + -@erase "$(OUTDIR)\mod_log_debug.exp" + -@erase "$(OUTDIR)\mod_log_debug.lib" + -@erase "$(OUTDIR)\mod_log_debug.pdb" + -@erase "$(OUTDIR)\mod_log_debug.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_log_debug_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_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_debug.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_debug.pdb" /debug /out:"$(OUTDIR)\mod_log_debug.so" /implib:"$(OUTDIR)\mod_log_debug.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so +LINK32_OBJS= \ + "$(INTDIR)\mod_log_debug.obj" \ + "$(INTDIR)\mod_log_debug.res" \ + "..\..\srclib\apr\Debug\libapr-1.lib" \ + "..\..\Debug\libhttpd.lib" + +"$(OUTDIR)\mod_log_debug.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\mod_log_debug.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_log_debug.so" + if exist .\Debug\mod_log_debug.so.manifest mt.exe -manifest .\Debug\mod_log_debug.so.manifest -outputresource:.\Debug\mod_log_debug.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("mod_log_debug.dep") +!INCLUDE "mod_log_debug.dep" +!ELSE +!MESSAGE Warning: cannot find "mod_log_debug.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "mod_log_debug - Win32 Release" || "$(CFG)" == "mod_log_debug - Win32 Debug" + +!IF "$(CFG)" == "mod_log_debug - Win32 Release" + +"libapr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" + cd "..\..\modules\loggers" + +"libapr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug" + +"libapr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" + cd "..\..\modules\loggers" + +"libapr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_log_debug - Win32 Release" + +"libhttpd - Win32 Release" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" + cd ".\modules\loggers" + +"libhttpd - Win32 ReleaseCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug" + +"libhttpd - Win32 Debug" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" + cd ".\modules\loggers" + +"libhttpd - Win32 DebugCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "mod_log_debug - Win32 Release" + + +"$(INTDIR)\mod_log_debug.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache" $(SOURCE) + + +!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug" + + +"$(INTDIR)\mod_log_debug.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache" $(SOURCE) + + +!ENDIF + +SOURCE=.\mod_log_debug.c + +"$(INTDIR)\mod_log_debug.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/modules/loggers/mod_log_forensic.c b/modules/loggers/mod_log_forensic.c new file mode 100644 index 0000000..bb808e8 --- /dev/null +++ b/modules/loggers/mod_log_forensic.c @@ -0,0 +1,289 @@ +/* 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. + */ + +/* + * See also support/check_forensic. + * Relate the forensic log to the transfer log by including + * %{forensic-id}n in the custom log format, for example: + * CustomLog logs/custom "%h %l %u %t \"%r\" %>s %b %{forensic-id}n" + * + * Credit is due to Tina Bird <tbird precision-guesswork.com>, whose + * idea this module was. + * + * Ben Laurie 29/12/2003 + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "apr_strings.h" +#include "apr_atomic.h" +#include "http_protocol.h" +#include "test_char.h" +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +module AP_MODULE_DECLARE_DATA log_forensic_module; + +typedef struct fcfg { + const char *logname; + apr_file_t *fd; +} fcfg; + +static apr_uint32_t next_id; + +static void *make_forensic_log_scfg(apr_pool_t *p, server_rec *s) +{ + fcfg *cfg = apr_pcalloc(p, sizeof *cfg); + + cfg->logname = NULL; + cfg->fd = NULL; + + return cfg; +} + +static void *merge_forensic_log_scfg(apr_pool_t *p, void *parent, void *new) +{ + fcfg *cfg = apr_pcalloc(p, sizeof *cfg); + fcfg *pc = parent; + fcfg *nc = new; + + cfg->logname = apr_pstrdup(p, nc->logname ? nc->logname : pc->logname); + cfg->fd = NULL; + + return cfg; +} + +static int open_log(server_rec *s, apr_pool_t *p) +{ + fcfg *cfg = ap_get_module_config(s->module_config, &log_forensic_module); + + if (!cfg->logname || cfg->fd) + return 1; + + if (*cfg->logname == '|') { + piped_log *pl; + const char *pname = ap_server_root_relative(p, cfg->logname + 1); + + pl = ap_open_piped_log(p, pname); + if (pl == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00650) + "couldn't spawn forensic log pipe %s", cfg->logname); + return 0; + } + cfg->fd = ap_piped_log_write_fd(pl); + } + else { + const char *fname = ap_server_root_relative(p, cfg->logname); + apr_status_t rv; + + if ((rv = apr_file_open(&cfg->fd, fname, + APR_WRITE | APR_APPEND | APR_CREATE, + APR_OS_DEFAULT, p)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00651) + "could not open forensic log file %s.", fname); + return 0; + } + } + + return 1; +} + +static int log_init(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, + server_rec *s) +{ + for ( ; s ; s = s->next) { + if (!open_log(s, p)) { + return HTTP_INTERNAL_SERVER_ERROR; + } + } + + return OK; +} + + +/* e is the first _invalid_ location in q + N.B. returns the terminating NUL. + */ +static char *log_escape(char *q, const char *e, const char *p) +{ + for ( ; *p ; ++p) { + ap_assert(q < e); + if (test_char_table[*(unsigned char *)p]&T_ESCAPE_FORENSIC) { + ap_assert(q+2 < e); + *q++ = '%'; + ap_bin2hex(p, 1, q); + q += 2; + } + else + *q++ = *p; + } + ap_assert(q < e); + *q = '\0'; + + return q; +} + +typedef struct hlog { + char *log; + char *pos; + char *end; + apr_pool_t *p; + apr_size_t count; +} hlog; + +static int count_string(const char *p) +{ + int n; + + for (n = 0 ; *p ; ++p, ++n) + if (test_char_table[*(unsigned char *)p]&T_ESCAPE_FORENSIC) + n += 2; + return n; +} + +static int count_headers(void *h_, const char *key, const char *value) +{ + hlog *h = h_; + + h->count += count_string(key)+count_string(value)+2; + + return 1; +} + +static int log_headers(void *h_, const char *key, const char *value) +{ + hlog *h = h_; + + /* note that we don't have to check h->pos here, coz its been done + for us by log_escape */ + *h->pos++ = '|'; + h->pos = log_escape(h->pos, h->end, key); + *h->pos++ = ':'; + h->pos = log_escape(h->pos, h->end, value); + + return 1; +} + +static int log_before(request_rec *r) +{ + fcfg *cfg = ap_get_module_config(r->server->module_config, + &log_forensic_module); + const char *id; + hlog h; + apr_size_t n; + apr_status_t rv; + + if (!cfg->fd || r->prev) { + return DECLINED; + } + + if (!(id = apr_table_get(r->subprocess_env, "UNIQUE_ID"))) { + /* we make the assumption that we can't go through all the PIDs in + under 1 second */ + id = apr_psprintf(r->pool, "%" APR_PID_T_FMT ":%lx:%x", getpid(), + time(NULL), apr_atomic_inc32(&next_id)); + } + ap_set_module_config(r->request_config, &log_forensic_module, (char *)id); + + h.p = r->pool; + h.count = 0; + + apr_table_do(count_headers, &h, r->headers_in, NULL); + + h.count += 1+strlen(id)+1+count_string(r->the_request)+1+1; + h.log = apr_palloc(r->pool, h.count); + h.pos = h.log; + h.end = h.log+h.count; + + *h.pos++ = '+'; + strcpy(h.pos, id); + h.pos += strlen(h.pos); + *h.pos++ = '|'; + h.pos = log_escape(h.pos, h.end, r->the_request); + + apr_table_do(log_headers, &h, r->headers_in, NULL); + + ap_assert(h.pos < h.end); + *h.pos++ = '\n'; + + n = h.count-1; + rv = apr_file_write(cfg->fd, h.log, &n); + ap_assert(rv == APR_SUCCESS && n == h.count-1); + + apr_table_setn(r->notes, "forensic-id", id); + + return OK; +} + +static int log_after(request_rec *r) +{ + fcfg *cfg = ap_get_module_config(r->server->module_config, + &log_forensic_module); + const char *id = ap_get_module_config(r->request_config, + &log_forensic_module); + char *s; + apr_size_t l, n; + apr_status_t rv; + + if (!cfg->fd || id == NULL) { + return DECLINED; + } + + s = apr_pstrcat(r->pool, "-", id, "\n", NULL); + l = n = strlen(s); + rv = apr_file_write(cfg->fd, s, &n); + ap_assert(rv == APR_SUCCESS && n == l); + + return OK; +} + +static const char *set_forensic_log(cmd_parms *cmd, void *dummy, const char *fn) +{ + fcfg *cfg = ap_get_module_config(cmd->server->module_config, + &log_forensic_module); + + cfg->logname = fn; + return NULL; +} + +static const command_rec forensic_log_cmds[] = +{ + AP_INIT_TAKE1("ForensicLog", set_forensic_log, NULL, RSRC_CONF, + "the filename of the forensic log"), + { NULL } +}; + +static void register_hooks(apr_pool_t *p) +{ + static const char * const pre[] = { "mod_unique_id.c", NULL }; + + ap_hook_open_logs(log_init,NULL,NULL,APR_HOOK_MIDDLE); + ap_hook_post_read_request(log_before,pre,NULL,APR_HOOK_REALLY_FIRST); + ap_hook_log_transaction(log_after,NULL,NULL,APR_HOOK_REALLY_LAST); +} + +AP_DECLARE_MODULE(log_forensic) = +{ + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config */ + NULL, /* merge per-dir config */ + make_forensic_log_scfg, /* server config */ + merge_forensic_log_scfg, /* merge server config */ + forensic_log_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; diff --git a/modules/loggers/mod_log_forensic.dep b/modules/loggers/mod_log_forensic.dep new file mode 100644 index 0000000..2337156 --- /dev/null +++ b/modules/loggers/mod_log_forensic.dep @@ -0,0 +1,53 @@ +# Microsoft Developer Studio Generated Dependency File, included by mod_log_forensic.mak + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + + +.\mod_log_forensic.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_protocol.h"\ + "..\..\include\httpd.h"\ + "..\..\include\os.h"\ + "..\..\include\util_cfgtree.h"\ + "..\..\include\util_filter.h"\ + "..\..\server\test_char.h"\ + "..\..\srclib\apr-util\include\apr_buckets.h"\ + "..\..\srclib\apr-util\include\apr_hooks.h"\ + "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ + "..\..\srclib\apr-util\include\apr_uri.h"\ + "..\..\srclib\apr-util\include\apu.h"\ + "..\..\srclib\apr\include\apr.h"\ + "..\..\srclib\apr\include\apr_allocator.h"\ + "..\..\srclib\apr\include\apr_atomic.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/loggers/mod_log_forensic.dsp b/modules/loggers/mod_log_forensic.dsp new file mode 100644 index 0000000..cdf7c21 --- /dev/null +++ b/modules/loggers/mod_log_forensic.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="mod_log_forensic" - 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_log_forensic - 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_log_forensic.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_log_forensic.mak" CFG="mod_log_forensic - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_log_forensic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_log_forensic - 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_log_forensic - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_log_forensic_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_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_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_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_log_forensic.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_log_forensic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_log_forensic_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_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_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_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_log_forensic.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_log_forensic - Win32 Release" +# Name "mod_log_forensic - Win32 Debug" +# Begin Source File + +SOURCE=.\mod_log_forensic.c +# End Source File +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/loggers/mod_log_forensic.exp b/modules/loggers/mod_log_forensic.exp new file mode 100644 index 0000000..92f5075 --- /dev/null +++ b/modules/loggers/mod_log_forensic.exp @@ -0,0 +1 @@ +log_forensic_module diff --git a/modules/loggers/mod_log_forensic.mak b/modules/loggers/mod_log_forensic.mak new file mode 100644 index 0000000..0ad2e54 --- /dev/null +++ b/modules/loggers/mod_log_forensic.mak @@ -0,0 +1,353 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on mod_log_forensic.dsp +!IF "$(CFG)" == "" +CFG=mod_log_forensic - Win32 Release +!MESSAGE No configuration specified. Defaulting to mod_log_forensic - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "mod_log_forensic - Win32 Release" && "$(CFG)" != "mod_log_forensic - 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_log_forensic.mak" CFG="mod_log_forensic - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_log_forensic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_log_forensic - 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_log_forensic - 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_log_forensic.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_log_forensic.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_log_forensic.obj" + -@erase "$(INTDIR)\mod_log_forensic.res" + -@erase "$(INTDIR)\mod_log_forensic_src.idb" + -@erase "$(INTDIR)\mod_log_forensic_src.pdb" + -@erase "$(OUTDIR)\mod_log_forensic.exp" + -@erase "$(OUTDIR)\mod_log_forensic.lib" + -@erase "$(OUTDIR)\mod_log_forensic.pdb" + -@erase "$(OUTDIR)\mod_log_forensic.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_forensic_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_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_forensic.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_forensic.pdb" /debug /out:"$(OUTDIR)\mod_log_forensic.so" /implib:"$(OUTDIR)\mod_log_forensic.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\mod_log_forensic.obj" \ + "$(INTDIR)\mod_log_forensic.res" \ + "..\..\srclib\apr\Release\libapr-1.lib" \ + "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ + "..\..\Release\libhttpd.lib" + +"$(OUTDIR)\mod_log_forensic.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\mod_log_forensic.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_log_forensic.so" + if exist .\Release\mod_log_forensic.so.manifest mt.exe -manifest .\Release\mod_log_forensic.so.manifest -outputresource:.\Release\mod_log_forensic.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "mod_log_forensic - 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_log_forensic.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_log_forensic.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_log_forensic.obj" + -@erase "$(INTDIR)\mod_log_forensic.res" + -@erase "$(INTDIR)\mod_log_forensic_src.idb" + -@erase "$(INTDIR)\mod_log_forensic_src.pdb" + -@erase "$(OUTDIR)\mod_log_forensic.exp" + -@erase "$(OUTDIR)\mod_log_forensic.lib" + -@erase "$(OUTDIR)\mod_log_forensic.pdb" + -@erase "$(OUTDIR)\mod_log_forensic.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_forensic_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_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_forensic.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_forensic.pdb" /debug /out:"$(OUTDIR)\mod_log_forensic.so" /implib:"$(OUTDIR)\mod_log_forensic.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so +LINK32_OBJS= \ + "$(INTDIR)\mod_log_forensic.obj" \ + "$(INTDIR)\mod_log_forensic.res" \ + "..\..\srclib\apr\Debug\libapr-1.lib" \ + "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ + "..\..\Debug\libhttpd.lib" + +"$(OUTDIR)\mod_log_forensic.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\mod_log_forensic.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_log_forensic.so" + if exist .\Debug\mod_log_forensic.so.manifest mt.exe -manifest .\Debug\mod_log_forensic.so.manifest -outputresource:.\Debug\mod_log_forensic.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("mod_log_forensic.dep") +!INCLUDE "mod_log_forensic.dep" +!ELSE +!MESSAGE Warning: cannot find "mod_log_forensic.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "mod_log_forensic - Win32 Release" || "$(CFG)" == "mod_log_forensic - Win32 Debug" + +!IF "$(CFG)" == "mod_log_forensic - Win32 Release" + +"libapr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" + cd "..\..\modules\loggers" + +"libapr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug" + +"libapr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" + cd "..\..\modules\loggers" + +"libapr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_log_forensic - Win32 Release" + +"libaprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" + cd "..\..\modules\loggers" + +"libaprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug" + +"libaprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" + cd "..\..\modules\loggers" + +"libaprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_log_forensic - Win32 Release" + +"libhttpd - Win32 Release" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" + cd ".\modules\loggers" + +"libhttpd - Win32 ReleaseCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug" + +"libhttpd - Win32 Debug" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" + cd ".\modules\loggers" + +"libhttpd - Win32 DebugCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "mod_log_forensic - Win32 Release" + + +"$(INTDIR)\mod_log_forensic.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache" $(SOURCE) + + +!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug" + + +"$(INTDIR)\mod_log_forensic.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache" $(SOURCE) + + +!ENDIF + +SOURCE=.\mod_log_forensic.c + +"$(INTDIR)\mod_log_forensic.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/modules/loggers/mod_logio.c b/modules/loggers/mod_logio.c new file mode 100644 index 0000000..b609f7f --- /dev/null +++ b/modules/loggers/mod_logio.c @@ -0,0 +1,284 @@ +/* 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. + */ + +/* + * Written by Bojan Smojver <bojan rexursive.com>. + */ + +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_hash.h" +#include "apr_optional.h" + +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#include "ap_config.h" +#include "mod_log_config.h" +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_connection.h" +#include "http_protocol.h" +#include "http_request.h" + +module AP_MODULE_DECLARE_DATA logio_module; + +static const char logio_filter_name[] = "LOG_INPUT_OUTPUT"; +static const char logio_ttfb_filter_name[] = "LOGIO_TTFB_OUT"; + +/* + * Logging of input and output config... + */ + +typedef struct logio_config_t { + apr_off_t bytes_in; + apr_off_t bytes_out; + apr_off_t bytes_last_request; +} logio_config_t; + +typedef struct logio_dirconf_t { + unsigned int track_ttfb:1; +} logio_dirconf_t; + +typedef struct logio_req_t { + apr_time_t ttfb; +} logio_req_t; + + + +/* + * Optional function for the core to add to bytes_out + */ + +static void ap_logio_add_bytes_out(conn_rec *c, apr_off_t bytes) +{ + logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module); + cf->bytes_out += bytes; +} + +/* + * Optional function for modules to adjust bytes_in + */ + +static void ap_logio_add_bytes_in(conn_rec *c, apr_off_t bytes) +{ + logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module); + + cf->bytes_in += bytes; +} + +/* + * Optional function to get total byte count of last request for + * ap_increment_counts. + */ + +static apr_off_t ap_logio_get_last_bytes(conn_rec *c) +{ + logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module); + + return cf->bytes_last_request; +} + +/* + * Format items... + */ + +static const char *log_bytes_in(request_rec *r, char *a) +{ + logio_config_t *cf = ap_get_module_config(r->connection->conn_config, + &logio_module); + + return apr_off_t_toa(r->pool, cf->bytes_in); +} + +static const char *log_bytes_out(request_rec *r, char *a) +{ + logio_config_t *cf = ap_get_module_config(r->connection->conn_config, + &logio_module); + + return apr_off_t_toa(r->pool, cf->bytes_out); +} + +static const char *log_bytes_combined(request_rec *r, char *a) +{ + logio_config_t *cf = ap_get_module_config(r->connection->conn_config, + &logio_module); + + return apr_off_t_toa(r->pool, cf->bytes_out + cf->bytes_in); +} + +static const char *log_ttfb(request_rec *r, char *a) +{ + logio_req_t *rconf = ap_get_module_config(r->request_config, + &logio_module); + + if (!rconf || !rconf->ttfb) { + return "-"; + } + + return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, rconf->ttfb); +} +/* + * Reset counters after logging... + */ + +static int logio_transaction(request_rec *r) +{ + logio_config_t *cf = ap_get_module_config(r->connection->conn_config, + &logio_module); + + /* need to save byte count of last request for ap_increment_counts */ + cf->bytes_last_request = cf->bytes_in + cf->bytes_out; + cf->bytes_in = cf->bytes_out = 0; + + return OK; +} + +/* + * Logging of input filter... + */ + +static apr_status_t logio_in_filter(ap_filter_t *f, + apr_bucket_brigade *bb, + ap_input_mode_t mode, + apr_read_type_e block, + apr_off_t readbytes) +{ + apr_off_t length; + apr_status_t status; + logio_config_t *cf = ap_get_module_config(f->c->conn_config, &logio_module); + + status = ap_get_brigade(f->next, bb, mode, block, readbytes); + + apr_brigade_length (bb, 0, &length); + + if (length > 0) + cf->bytes_in += length; + + return status; +} + +/* + * The hooks... + */ + +static int logio_pre_conn(conn_rec *c, void *csd) +{ + logio_config_t *cf = apr_pcalloc(c->pool, sizeof(*cf)); + + ap_set_module_config(c->conn_config, &logio_module, cf); + + ap_add_input_filter(logio_filter_name, NULL, NULL, c); + + return OK; +} + +static int logio_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) +{ + APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; + + log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); + + if (log_pfn_register) { + log_pfn_register(p, "I", log_bytes_in, 0); + log_pfn_register(p, "O", log_bytes_out, 0); + log_pfn_register(p, "S", log_bytes_combined, 0); + log_pfn_register(p, "^FB", log_ttfb, 0); + } + + return OK; +} + +static apr_status_t logio_ttfb_filter(ap_filter_t *f, apr_bucket_brigade *b) +{ + request_rec *r = f->r; + logio_dirconf_t *conf = ap_get_module_config(r->per_dir_config, + &logio_module); + if (conf && conf->track_ttfb) { + logio_req_t *rconf = ap_get_module_config(r->request_config, + &logio_module); + if (rconf == NULL) { + rconf = apr_pcalloc(r->pool, sizeof(logio_req_t)); + rconf->ttfb = apr_time_now() - r->request_time; + ap_set_module_config(r->request_config, &logio_module, rconf); + } + } + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, b); +} + +static void logio_insert_filter(request_rec * r) +{ + logio_dirconf_t *conf = ap_get_module_config(r->per_dir_config, + &logio_module); + if (conf->track_ttfb) { + ap_add_output_filter(logio_ttfb_filter_name, NULL, r, r->connection); + } +} + +static const char *logio_track_ttfb(cmd_parms *cmd, void *in_dir_config, int arg) +{ + logio_dirconf_t *dir_config = in_dir_config; + dir_config->track_ttfb = arg; + return NULL; +} + +static void *create_logio_dirconf (apr_pool_t *p, char *dummy) +{ + logio_dirconf_t *new = + (logio_dirconf_t *) apr_pcalloc(p, sizeof(logio_dirconf_t)); + return (void *) new; +} + + +static const command_rec logio_cmds[] = { + AP_INIT_FLAG ("LogIOTrackTTFB", logio_track_ttfb, NULL, OR_ALL, + "Set to 'ON' to enable tracking time to first byte"), + {NULL} +}; + + +static void register_hooks(apr_pool_t *p) +{ + static const char *pre[] = { "mod_log_config.c", NULL }; + + ap_hook_pre_connection(logio_pre_conn, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_pre_config(logio_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); + ap_hook_log_transaction(logio_transaction, pre, NULL, APR_HOOK_MIDDLE); + + ap_register_input_filter(logio_filter_name, logio_in_filter, NULL, + AP_FTYPE_NETWORK - 1); + + ap_hook_insert_filter(logio_insert_filter, NULL, NULL, APR_HOOK_LAST); + ap_register_output_filter(logio_ttfb_filter_name, logio_ttfb_filter, NULL, + AP_FTYPE_RESOURCE); + + APR_REGISTER_OPTIONAL_FN(ap_logio_add_bytes_out); + APR_REGISTER_OPTIONAL_FN(ap_logio_add_bytes_in); + APR_REGISTER_OPTIONAL_FN(ap_logio_get_last_bytes); +} + +AP_DECLARE_MODULE(logio) = +{ + STANDARD20_MODULE_STUFF, + create_logio_dirconf, /* create per-dir config */ + NULL, /* merge per-dir config */ + NULL, /* server config */ + NULL, /* merge server config */ + logio_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; diff --git a/modules/loggers/mod_logio.dep b/modules/loggers/mod_logio.dep new file mode 100644 index 0000000..cc70d81 --- /dev/null +++ b/modules/loggers/mod_logio.dep @@ -0,0 +1,59 @@ +# Microsoft Developer Studio Generated Dependency File, included by mod_logio.mak + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + + +.\mod_logio.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_connection.h"\ + "..\..\include\http_core.h"\ + "..\..\include\http_protocol.h"\ + "..\..\include\http_request.h"\ + "..\..\include\httpd.h"\ + "..\..\include\os.h"\ + "..\..\include\scoreboard.h"\ + "..\..\include\util_cfgtree.h"\ + "..\..\include\util_filter.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_log_config.h"\ + diff --git a/modules/loggers/mod_logio.dsp b/modules/loggers/mod_logio.dsp new file mode 100644 index 0000000..f5a8186 --- /dev/null +++ b/modules/loggers/mod_logio.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="mod_logio" - 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_logio - 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_logio.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_logio.mak" CFG="mod_logio - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_logio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_logio - 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_logio - 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_logio_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_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_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_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\mod_logio.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_logio - 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_logio_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_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_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_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so +# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so +# Begin Special Build Tool +TargetPath=.\Debug\mod_logio.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_logio - Win32 Release" +# Name "mod_logio - Win32 Debug" +# Begin Source File + +SOURCE=.\mod_logio.c +# End Source File +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/modules/loggers/mod_logio.mak b/modules/loggers/mod_logio.mak new file mode 100644 index 0000000..363e848 --- /dev/null +++ b/modules/loggers/mod_logio.mak @@ -0,0 +1,353 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on mod_logio.dsp +!IF "$(CFG)" == "" +CFG=mod_logio - Win32 Release +!MESSAGE No configuration specified. Defaulting to mod_logio - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "mod_logio - Win32 Release" && "$(CFG)" != "mod_logio - 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_logio.mak" CFG="mod_logio - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_logio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_logio - 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_logio - 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_logio.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_logio.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_logio.obj" + -@erase "$(INTDIR)\mod_logio.res" + -@erase "$(INTDIR)\mod_logio_src.idb" + -@erase "$(INTDIR)\mod_logio_src.pdb" + -@erase "$(OUTDIR)\mod_logio.exp" + -@erase "$(OUTDIR)\mod_logio.lib" + -@erase "$(OUTDIR)\mod_logio.pdb" + -@erase "$(OUTDIR)\mod_logio.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_logio_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_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_logio.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_logio.pdb" /debug /out:"$(OUTDIR)\mod_logio.so" /implib:"$(OUTDIR)\mod_logio.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\mod_logio.obj" \ + "$(INTDIR)\mod_logio.res" \ + "..\..\srclib\apr\Release\libapr-1.lib" \ + "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ + "..\..\Release\libhttpd.lib" + +"$(OUTDIR)\mod_logio.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\mod_logio.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_logio.so" + if exist .\Release\mod_logio.so.manifest mt.exe -manifest .\Release\mod_logio.so.manifest -outputresource:.\Release\mod_logio.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "mod_logio - 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_logio.so" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_logio.so" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\mod_logio.obj" + -@erase "$(INTDIR)\mod_logio.res" + -@erase "$(INTDIR)\mod_logio_src.idb" + -@erase "$(INTDIR)\mod_logio_src.pdb" + -@erase "$(OUTDIR)\mod_logio.exp" + -@erase "$(OUTDIR)\mod_logio.lib" + -@erase "$(OUTDIR)\mod_logio.pdb" + -@erase "$(OUTDIR)\mod_logio.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_logio_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_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_logio.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_logio.pdb" /debug /out:"$(OUTDIR)\mod_logio.so" /implib:"$(OUTDIR)\mod_logio.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so +LINK32_OBJS= \ + "$(INTDIR)\mod_logio.obj" \ + "$(INTDIR)\mod_logio.res" \ + "..\..\srclib\apr\Debug\libapr-1.lib" \ + "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ + "..\..\Debug\libhttpd.lib" + +"$(OUTDIR)\mod_logio.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\mod_logio.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_logio.so" + if exist .\Debug\mod_logio.so.manifest mt.exe -manifest .\Debug\mod_logio.so.manifest -outputresource:.\Debug\mod_logio.so;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("mod_logio.dep") +!INCLUDE "mod_logio.dep" +!ELSE +!MESSAGE Warning: cannot find "mod_logio.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "mod_logio - Win32 Release" || "$(CFG)" == "mod_logio - Win32 Debug" + +!IF "$(CFG)" == "mod_logio - Win32 Release" + +"libapr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" + cd "..\..\modules\loggers" + +"libapr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug" + +"libapr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" + cd "..\..\modules\loggers" + +"libapr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_logio - Win32 Release" + +"libaprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" + cd "..\..\modules\loggers" + +"libaprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug" + +"libaprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" + cd "..\..\modules\loggers" + +"libaprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\modules\loggers" + +!ENDIF + +!IF "$(CFG)" == "mod_logio - Win32 Release" + +"libhttpd - Win32 Release" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" + cd ".\modules\loggers" + +"libhttpd - Win32 ReleaseCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug" + +"libhttpd - Win32 Debug" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" + cd ".\modules\loggers" + +"libhttpd - Win32 DebugCLEAN" : + cd ".\..\.." + $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN + cd ".\modules\loggers" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "mod_logio - Win32 Release" + + +"$(INTDIR)\mod_logio.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache" $(SOURCE) + + +!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug" + + +"$(INTDIR)\mod_logio.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache" $(SOURCE) + + +!ENDIF + +SOURCE=.\mod_logio.c + +"$(INTDIR)\mod_logio.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + |