Cliff Woolley wrote:
> On Wed, 9 Jun 2004, Geoffrey Young wrote:
>
>
>>I wanted to ping everyone about an idea I've been throwing around for a few
>>months now. I'd like the ability to shuffle the declared hook ordering
>>around, most likely during the post-config phase.
>
>
> There was some discussion about this or something at least vaguely like it
> a while back, but nobody ever got around to implementing it.
ok, here's a first pass at just a small part - achieve the hook listing by
offering an apr_table_do()-esque iterator just for hooks.
the output of httpd -o (for hOok, I guess) looks something like this:
Registered Hooks:
Pre-MPM
core.c (10)
...
Open Logs
prefork.c (10)
core.c (-10)
mod_log_config.c (10)
...
Map-to-Storage
mod_proxy.c (0)
http_core.c (10)
core.c (30)
etc.
where the number in parentheses is the (untranslated) APR_HOOK_* value.
this is obviously a work in progress (and perhaps ugly as well), so comments
on all aspects very, very welcome. the next step would to make mod_info use
the new hook iterator and pull out the logic that was mostly stolen from
there. but I'll wait for feedback on what I have so far before doing that,
as well as stuff like ap_hook_order_set() or somesuch :)
--Geoff
Index: NWGNUmakefile
===================================================================
RCS file: /home/cvs/httpd-2.0/NWGNUmakefile,v
retrieving revision 1.25
diff -u -r1.25 NWGNUmakefile
--- NWGNUmakefile 1 Jun 2004 17:48:21 -0000 1.25
+++ NWGNUmakefile 11 Jun 2004 04:33:46 -0000
@@ -238,6 +238,7 @@
$(OBJDIR)/util_md5.o \
$(OBJDIR)/util_nw.o \
$(OBJDIR)/util_script.o \
+ $(OBJDIR)/util_hook.o \
$(OBJDIR)/util_time.o \
$(OBJDIR)/util_xml.o \
$(OBJDIR)/vhost.o \
Index: build/nw_export.inc
===================================================================
RCS file: /home/cvs/httpd-2.0/build/nw_export.inc,v
retrieving revision 1.5
diff -u -r1.5 nw_export.inc
--- build/nw_export.inc 20 Jan 2003 21:38:49 -0000 1.5
+++ build/nw_export.inc 11 Jun 2004 04:34:03 -0000
@@ -42,6 +42,7 @@
/*#include "util_ldap.h"*/
#include "util_md5.h"
#include "util_script.h"
+#include "util_hook.h"
#include "util_time.h"
#include "util_xml.h"
Index: include/http_config.h
===================================================================
RCS file: /home/cvs/httpd-2.0/include/http_config.h,v
retrieving revision 1.110
diff -u -r1.110 http_config.h
--- include/http_config.h 4 Jun 2004 22:40:46 -0000 1.110
+++ include/http_config.h 11 Jun 2004 04:34:06 -0000
@@ -768,6 +768,11 @@
AP_DECLARE(void) ap_show_modules(void);
/**
+ * Show registered hooks. Used for httpd -k.
+ */
+AP_DECLARE(void) ap_show_hooks(void);
+
+/**
* Show the MPM name. Used in reporting modules such as mod_info to
* provide extra information to the user
*/
Index: include/http_main.h
===================================================================
RCS file: /home/cvs/httpd-2.0/include/http_main.h,v
retrieving revision 1.30
diff -u -r1.30 http_main.h
--- include/http_main.h 9 Feb 2004 20:38:21 -0000 1.30
+++ include/http_main.h 11 Jun 2004 04:34:08 -0000
@@ -22,7 +22,7 @@
* in apr_getopt() format. Use this for default'ing args that the MPM
* can safely ignore and pass on from its rewrite_args() handler.
*/
-#define AP_SERVER_BASEARGS "C:c:D:d:E:e:f:vVlLtSh?X"
+#define AP_SERVER_BASEARGS "C:c:D:d:E:e:f:vVloLtSh?X"
#ifdef __cplusplus
extern "C" {
Index: server/Makefile.in
===================================================================
RCS file: /home/cvs/httpd-2.0/server/Makefile.in,v
retrieving revision 1.94
diff -u -r1.94 Makefile.in
--- server/Makefile.in 15 Mar 2004 21:49:35 -0000 1.94
+++ server/Makefile.in 11 Jun 2004 04:36:29 -0000
@@ -9,7 +9,7 @@
LTLIBRARY_SOURCES = \
test_char.h \
config.c log.c main.c vhost.c util.c \
- util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c \
+ util_script.c util_md5.c util_cfgtree.c util_ebcdic.c util_time.c util_hook.c \
connection.c listen.c \
mpm_common.c util_charset.c util_debug.c util_xml.c \
util_filter.c exports.c buildmark.c \
@@ -66,6 +66,8 @@
export_vars.h: export_files
$(AWK) -f $(top_srcdir)/build/make_var_export.awk `cat $?` > $@
+
+util_hook.c: httpd.exp
# Rule to make def file for OS/2 core dll
ApacheCoreOS2.def: exports.c export_vars.h $(top_srcdir)/os/$(OS_DIR)/core_header.def
Index: server/config.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/config.c,v
retrieving revision 1.177
diff -u -r1.177 config.c
--- server/config.c 25 Apr 2004 17:23:31 -0000 1.177
+++ server/config.c 11 Jun 2004 04:36:32 -0000
@@ -50,6 +50,7 @@
#include "http_main.h"
#include "http_vhost.h"
#include "util_cfgtree.h"
+#include "util_hook.h"
#include "mpm.h"
@@ -2047,4 +2048,28 @@
AP_DECLARE(const char *) ap_show_mpm(void)
{
return MPM_NAME;
+}
+
+static int list_hooks(char **phase, ap_hook_struct_t *hook)
+{
+ if (strcmp(*phase, hook->desc)) {
+ printf(" %s\n", hook->desc);
+ }
+
+ printf(" %s (%d)\n", hook->module, hook->order);
+
+ *phase = hook->desc;
+
+ return 1;
+}
+
+/* Show the registered hooks. Used for httpd -k. */
+AP_DECLARE(void) ap_show_hooks()
+{
+ char *phase;
+
+ printf("Registered Hooks:\n");
+
+ ap_hook_do((int (*) (void *, ap_hook_struct_t *))
+ list_hooks, &phase, 0);
}
Index: server/main.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/main.c,v
retrieving revision 1.157
diff -u -r1.157 main.c
--- server/main.c 25 Apr 2004 17:23:31 -0000 1.157
+++ server/main.c 11 Jun 2004 04:36:42 -0000
@@ -379,6 +379,8 @@
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" -l : list compiled in modules");
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ " -o : list of registred hooks");
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" -L : list available configuration "
"directives");
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
@@ -396,6 +398,7 @@
{
char c;
int configtestonly = 0;
+ int listhooks = 0;
const char *confname = SERVER_CONFIG_FILE;
const char *def_server_root = HTTPD_ROOT;
const char *temp_error_log = NULL;
@@ -544,6 +547,11 @@
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DUMP_VHOSTS";
break;
+
+ case 'o':
+ listhooks = 1;
+ break;
+
case 'h':
case '?':
@@ -590,6 +598,10 @@
apr_hook_sort_all();
if (configtestonly) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK");
+ destroy_and_exit_process(process, 0);
+ }
+ if (listhooks) {
+ ap_show_hooks();
destroy_and_exit_process(process, 0);
}
}
--- /dev/null 2003-09-15 09:40:47.000000000 -0400
+++ include/util_hook.h 2004-06-11 00:31:50.000000000 -0400
@@ -0,0 +1,154 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef APACHE_UTIL_HOOK_H
+#define APACHE_UTIL_HOOK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @package Apache hook tools
+ */
+
+typedef enum {
+ AP_HOOK_PRE_MPM = 1,
+ AP_HOOK_PRE_CONFIG,
+ AP_HOOK_POST_CONFIG,
+ AP_HOOK_OPEN_LOGS,
+ AP_HOOK_ERROR_LOG,
+ AP_HOOK_CHILD_INIT,
+ AP_HOOK_PRE_CONNECTION,
+ AP_HOOK_CREATE_CONNECTION,
+ AP_HOOK_PROCESS_CONNECTION,
+ AP_HOOK_CREATE_REQUEST,
+ AP_HOOK_POST_READ_REQUEST,
+ AP_HOOK_TRANSLATE_NAME,
+ AP_HOOK_MAP_TO_STORAGE,
+ AP_HOOK_HEADER_PARSER,
+ AP_HOOK_ACCESS_CHECKER,
+ AP_HOOK_CHECK_USER_ID,
+ AP_HOOK_AUTH_CHECKER,
+ AP_HOOK_TYPE_CHECKER,
+ AP_HOOK_FIXUPS,
+ AP_HOOK_HANDLER,
+ AP_HOOK_QUICK_HANDLER,
+ AP_HOOK_LOG_TRANSACTION,
+ AP_HOOK_INSERT_FILTER,
+ AP_HOOK_INSERT_ERROR_FILTER,
+ AP_HOOK_HTTP_METHOD,
+ AP_HOOK_DEFAULT_PORT
+} ap_hook_e;
+
+
+/* private - this really should be coming from apr_hooks.h, but
+ * everything there is wrapped in macros and specific to each hook,
+ * so there is nothing generic for us to pull from. also, we don't
+ * really want to open up predecessor logic, as messing with that
+ * could really mess things up.
+ */
+typedef struct {
+ void (*pFunc)(void); /* just to get the right size */
+ const char *szName;
+ const char * const *aszPredecessors;
+ const char * const *aszSuccessors;
+ int nOrder;
+} hook_struct_t;
+
+/* public - ap_table_do callbacks will receive this structure. it's
+ * a bit different than the official one from apr_hooks.h in that
+ * the list of successors and predecessors is missing for safety
+ * and the field names are a bit more intuitive.
+ */
+typedef struct {
+ char *module;
+ char *desc;
+ int type;
+ int order;
+} ap_hook_struct_t;
+
+/*
+ * hook_get_t is a pointer to a function that takes void as an argument and
+ * returns a pointer to an apr_array_header_t. The nasty WIN32 ifdef
+ * is required to account for the fact that the ap_hook* calls all use
+ * STDCALL calling convention.
+ */
+typedef apr_array_header_t * (
+#ifdef WIN32
+__stdcall
+#endif
+* hook_get_t)(void);
+
+/* private - no ap_ prefix */
+typedef struct {
+ int type; /* AP_HOOK_HANDLER, etc */
+ char *desc; /* long name, "Verify Client ID" */
+ hook_get_t get; /* retrieval function */
+} hook_lookup_t;
+
+/**
+ * Declaration prototype for the iterator callback function of ap_hook_do()
+ * @param rec The data passed as the first argument to ap_hook_[v]do()
+ * @param hook The hook structure from this iteration of the table
+ * @remark Iteration continues while this callback function returns non-zero.
+ * To export the callback function for ap_hook_do() it must be declared
+ * in the _NONSTD convention.
+ */
+typedef int (ap_hook_do_callback_fn_t)(void *rec, ap_hook_struct_t *hook);
+
+
+/**
+ * Iterate over all registered hooks, running the provided function once for
+ * every hook. If there is non-zero (integer) data passed in as a vararg,
+ * then the function is only run on those hooks whose type matches something
+ * in the vararg. If the vararg is 0, then every hook is run through the
+ * function. Iteration continues while the function returns non-zero.
+ * @param comp The function to run
+ * @param rec The data to pass as the first argument to the function
+ * @param ... The vararg. If this is 0, then all registered hooks are
+ * run through the function, otherwise only those whose type matches
+ * are run.
+ * @return FALSE if one of the comp() iterations returned zero; TRUE if all
+ * iterations returned non-zero
+ * @see ap_hook_do_callback_fn_t
+ */
+APR_DECLARE_NONSTD(int) ap_hook_do(ap_hook_do_callback_fn_t *comp,
+ void *rec, ...);
+
+/**
+ * Iterate over all registered hooks, running the provided function once for
+ * every hook. If there is non-zero (integer) data passed in as a vararg,
+ * then the function is only run on those hooks whose type matches something
+ * in the vararg. If the vararg is 0, then every hook is run through the
+ * function. Iteration continues while the function returns non-zero.
+ * @param comp The function to run
+ * @param rec The data to pass as the first argument to the function
+ * @param ... The vararg. If this is 0, then all registered hooks are
+ * run through the function, otherwise only those whose type matches
+ * are run.
+ * @return FALSE if one of the comp() iterations returned zero; TRUE if all
+ * iterations returned non-zero
+ * @see ap_hook_do_callback_fn_t
+ */
+APR_DECLARE(int) ap_hook_vdo(ap_hook_do_callback_fn_t *comp,
+ void *rec, va_list vp);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !APACHE_UTIL_HOOK_H */
--- /dev/null 2003-09-15 09:40:47.000000000 -0400
+++ server/util_hook.c 2004-06-11 00:26:19.000000000 -0400
@@ -0,0 +1,151 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "httpd.h"
+
+#include "http_config.h"
+#include "http_request.h"
+#include "http_protocol.h"
+#include "http_log.h"
+
+#include "http_connection.h"
+#include "scoreboard.h"
+#include "apr_lib.h"
+#include "apr_hooks.h"
+#include "util_hook.h"
+
+static hook_lookup_t all_hooks[] = {
+ {AP_HOOK_PRE_MPM,
+ "Pre-MPM", ap_hook_get_pre_mpm},
+ {AP_HOOK_PRE_CONFIG,
+ "Pre-Configuration", ap_hook_get_pre_config},
+ {AP_HOOK_POST_CONFIG,
+ "Post-Configuration", ap_hook_get_post_config},
+ {AP_HOOK_OPEN_LOGS,
+ "Open Logs", ap_hook_get_open_logs},
+ {AP_HOOK_ERROR_LOG,
+ "Open Error Log", ap_hook_get_error_log},
+ {AP_HOOK_CHILD_INIT,
+ "Child Initialization", ap_hook_get_child_init},
+ {AP_HOOK_PRE_CONNECTION,
+ "Pre-Connection", ap_hook_get_pre_connection},
+ {AP_HOOK_CREATE_CONNECTION,
+ "Create Connection", ap_hook_get_create_connection},
+ {AP_HOOK_PROCESS_CONNECTION,
+ "Process Connection", ap_hook_get_process_connection},
+ {AP_HOOK_CREATE_REQUEST,
+ "Create Request", ap_hook_get_create_request},
+ {AP_HOOK_POST_READ_REQUEST,
+ "Post-Read Request", ap_hook_get_post_read_request},
+ {AP_HOOK_TRANSLATE_NAME,
+ "Translate Path", ap_hook_get_translate_name},
+ {AP_HOOK_MAP_TO_STORAGE,
+ "Map-to-Storage", ap_hook_get_map_to_storage},
+ {AP_HOOK_HEADER_PARSER,
+ "Header Parse", ap_hook_get_header_parser},
+ {AP_HOOK_ACCESS_CHECKER,
+ "Check Access", ap_hook_get_access_checker},
+ {AP_HOOK_CHECK_USER_ID,
+ "Verify User Id", ap_hook_get_check_user_id},
+ {AP_HOOK_AUTH_CHECKER,
+ "Verify User Access", ap_hook_get_auth_checker},
+ {AP_HOOK_TYPE_CHECKER,
+ "Check Type", ap_hook_get_type_checker},
+ {AP_HOOK_FIXUPS,
+ "Fixups", ap_hook_get_fixups},
+ {AP_HOOK_HANDLER,
+ "Content Handler", ap_hook_get_handler},
+ {AP_HOOK_QUICK_HANDLER,
+ "Content Quick Handler", ap_hook_get_quick_handler},
+ {AP_HOOK_LOG_TRANSACTION,
+ "Logging", ap_hook_get_log_transaction},
+ {AP_HOOK_INSERT_FILTER,
+ "Insert Filter", ap_hook_get_insert_filter},
+ {AP_HOOK_INSERT_ERROR_FILTER,
+ "Insert Error Filter", ap_hook_get_insert_error_filter},
+ {AP_HOOK_HTTP_METHOD,
+ "HTTP Method", ap_hook_get_http_method},
+ {AP_HOOK_DEFAULT_PORT,
+ "Default Port", ap_hook_get_default_port},
+};
+
+APR_DECLARE_NONSTD(int) ap_hook_do(ap_hook_do_callback_fn_t *comp,
+ void *rec, ...)
+{
+ int rv;
+
+ va_list vp;
+ va_start(vp, rec);
+ rv = ap_hook_vdo(comp, rec, vp);
+ va_end(vp);
+
+ return rv;
+}
+
+APR_DECLARE(int) ap_hook_vdo(ap_hook_do_callback_fn_t *comp,
+ void *rec, va_list vp)
+{
+ int i, j, type;
+
+ type = va_arg(vp, int);
+
+ do {
+ for (i = 0; i < sizeof(all_hooks)/sizeof(*all_hooks); i++) {
+ apr_array_header_t *hooks = all_hooks[i].get();
+ hook_struct_t *elts;
+ ap_hook_struct_t *hook;
+
+ if (!hooks) {
+ continue;
+ }
+
+ elts = (hook_struct_t *)hooks->elts;
+
+ int rv = 1;
+ if (type) {
+ /* process entries that match the hook type */
+ if (all_hooks[i].type == type) {
+ for (j = 0; j < hooks->nelts; j++) {
+ hook->module = (char *)elts[j].szName;
+ hook->desc = all_hooks[i].desc;
+ hook->type = all_hooks[i].type;
+ hook->order = elts[j].nOrder;
+
+ /* callback */
+ rv = (*comp) (rec, hook);
+ }
+ }
+ }
+ else {
+ /* process all registered hooks */
+ for (j = 0; j < hooks->nelts; j++) {
+ hook->module = (char *)elts[j].szName;
+ hook->desc = all_hooks[i].desc;
+ hook->type = all_hooks[i].type;
+ hook->order = elts[j].nOrder;
+
+ /* callback */
+ rv = (*comp) (rec, hook);
+ }
+ }
+ if (rv == 0) {
+ /* return immediately */
+ return 0;
+ }
+ }
+ } while (type && (type = va_arg(vp, int)));
+
+ return 1;
+}