1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Info Module. Display configuration information for the server and
19 * all included modules.
21 * <Location /server-info>
22 * SetHandler server-info
25 * GET /server-info - Returns full configuration page for server and all modules
26 * GET /server-info?server - Returns server configuration only
27 * GET /server-info?module_name - Returns configuration for a single module
28 * GET /server-info?list - Returns quick list of included modules
29 * GET /server-info?config - Returns full configuration
30 * GET /server-info?hooks - Returns a listing of the modules active for each hook
33 * Rasmus Lerdorf <rasmus vex.net>, May 1996
36 * Lou Langholtz <ldl usi.utah.edu>, July 1997
39 * Ryan Morgan <rmorgan covalent.net>, August 2000
45 #include "apr_strings.h"
47 #include "apr_version.h"
48 #define APR_WANT_STRFUNC
52 #include "http_config.h"
53 #include "http_core.h"
55 #include "http_main.h"
56 #include "http_protocol.h"
57 #include "http_connection.h"
58 #include "http_request.h"
59 #include "util_script.h"
64 const char *name; /* matching module name */
65 const char *info; /* additional info */
70 apr_array_header_t *more_info;
73 module AP_MODULE_DECLARE_DATA info_module;
75 static void *create_info_config(apr_pool_t * p, server_rec * s)
78 (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf));
80 conf->more_info = apr_array_make(p, 20, sizeof(info_entry));
84 static void *merge_info_config(apr_pool_t * p, void *basev, void *overridesv)
87 (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf));
88 info_svr_conf *base = (info_svr_conf *) basev;
89 info_svr_conf *overrides = (info_svr_conf *) overridesv;
92 apr_array_append(p, overrides->more_info, base->more_info);
96 static void put_int_flush_right(request_rec * r, int i, int field)
98 if (field > 1 || i > 9)
99 put_int_flush_right(r, i / 10, field - 1);
101 ap_rputc('0' + i % 10, r);
103 ap_rputs(" ", r);
106 static void mod_info_indent(request_rec * r, int nest,
107 const char *thisfn, int linenum)
111 ap_get_module_config(r->request_config, &info_module);
113 thisfn = "*UNKNOWN*";
114 if (prevfn == NULL || 0 != strcmp(prevfn, thisfn)) {
115 thisfn = ap_escape_html(r->pool, thisfn);
116 ap_rprintf(r, "<dd><tt><strong>In file: %s</strong></tt></dd>\n",
118 ap_set_module_config(r->request_config, &info_module,
122 ap_rputs("<dd><tt>", r);
123 put_int_flush_right(r, linenum > 0 ? linenum : 0, 4);
124 ap_rputs(": ", r);
126 for (i = 1; i <= nest; ++i) {
127 ap_rputs(" ", r);
131 static void mod_info_show_cmd(request_rec * r, const ap_directive_t * dir,
134 mod_info_indent(r, nest, dir->filename, dir->line_num);
135 ap_rprintf(r, "%s <i>%s</i></tt></dd>\n",
136 ap_escape_html(r->pool, dir->directive),
137 ap_escape_html(r->pool, dir->args));
140 static void mod_info_show_open(request_rec * r, const ap_directive_t * dir,
143 mod_info_indent(r, nest, dir->filename, dir->line_num);
144 ap_rprintf(r, "%s %s</tt></dd>\n",
145 ap_escape_html(r->pool, dir->directive),
146 ap_escape_html(r->pool, dir->args));
149 static void mod_info_show_close(request_rec * r, const ap_directive_t * dir,
152 const char *dirname = dir->directive;
153 mod_info_indent(r, nest, dir->filename, 0);
154 if (*dirname == '<') {
155 ap_rprintf(r, "</%s></tt></dd>",
156 ap_escape_html(r->pool, dirname + 1));
159 ap_rprintf(r, "/%s</tt></dd>", ap_escape_html(r->pool, dirname));
163 static int mod_info_has_cmd(const command_rec * cmds, ap_directive_t * dir)
165 const command_rec *cmd;
168 for (cmd = cmds; cmd->name; ++cmd) {
169 if (strcasecmp(cmd->name, dir->directive) == 0)
175 static void mod_info_show_parents(request_rec * r, ap_directive_t * node,
179 mod_info_show_parents(r, node->parent, from, to - 1);
180 mod_info_show_open(r, node, to);
183 static int mod_info_module_cmds(request_rec * r, const command_rec * cmds,
184 ap_directive_t * node, int from, int level)
189 ap_set_module_config(r->request_config, &info_module, NULL);
190 for (dir = node; dir; dir = dir->next) {
191 if (dir->first_child != NULL) {
192 if (level < mod_info_module_cmds(r, cmds, dir->first_child,
195 mod_info_show_close(r, dir, level);
198 else if (mod_info_has_cmd(cmds, dir)) {
200 mod_info_show_parents(r, dir->parent, shown, level - 1);
203 mod_info_show_cmd(r, dir, level);
210 { /*XXX: should get something from apr_hooks.h instead */
211 void (*pFunc) (void); /* just to get the right size */
213 const char *const *aszPredecessors;
214 const char *const *aszSuccessors;
219 * hook_get_t is a pointer to a function that takes void as an argument and
220 * returns a pointer to an apr_array_header_t. The nasty WIN32 ifdef
221 * is required to account for the fact that the ap_hook* calls all use
222 * STDCALL calling convention.
224 typedef apr_array_header_t *(
228 * hook_get_t) (void);
236 static hook_lookup_t startup_hooks[] = {
237 {"Pre-Config", ap_hook_get_pre_config},
238 {"Check Configuration", ap_hook_get_check_config},
239 {"Test Configuration", ap_hook_get_test_config},
240 {"Post Configuration", ap_hook_get_post_config},
241 {"Open Logs", ap_hook_get_open_logs},
242 {"Child Init", ap_hook_get_child_init},
246 static hook_lookup_t request_hooks[] = {
247 {"Pre-Connection", ap_hook_get_pre_connection},
248 {"Create Connection", ap_hook_get_create_connection},
249 {"Process Connection", ap_hook_get_process_connection},
250 {"Create Request", ap_hook_get_create_request},
251 {"Post-Read Request", ap_hook_get_post_read_request},
252 {"Header Parse", ap_hook_get_header_parser},
253 {"HTTP Scheme", ap_hook_get_http_scheme},
254 {"Default Port", ap_hook_get_default_port},
255 {"Quick Handler", ap_hook_get_quick_handler},
256 {"Translate Name", ap_hook_get_translate_name},
257 {"Map to Storage", ap_hook_get_map_to_storage},
258 {"Check Access", ap_hook_get_access_checker},
259 {"Verify User ID", ap_hook_get_check_user_id},
260 {"Verify User Access", ap_hook_get_auth_checker},
261 {"Check Type", ap_hook_get_type_checker},
262 {"Fixups", ap_hook_get_fixups},
263 {"Insert Filters", ap_hook_get_insert_filter},
264 {"Content Handlers", ap_hook_get_handler},
265 {"Logging", ap_hook_get_log_transaction},
266 {"Insert Errors", ap_hook_get_insert_error_filter},
270 static int module_find_hook(module * modp, hook_get_t hook_get)
273 apr_array_header_t *hooks = hook_get();
280 elts = (hook_struct_t *) hooks->elts;
282 for (i = 0; i < hooks->nelts; i++) {
283 if (strcmp(elts[i].szName, modp->name) == 0) {
291 static void module_participate(request_rec * r,
293 hook_lookup_t * lookup, int *comma)
295 if (module_find_hook(modp, lookup->get)) {
299 ap_rvputs(r, "<tt>", lookup->name, "</tt>", NULL);
304 static void module_request_hook_participate(request_rec * r, module * modp)
308 ap_rputs("<dt><strong>Request Phase Participation:</strong>\n", r);
310 for (i = 0; request_hooks[i].name; i++) {
311 module_participate(r, modp, &request_hooks[i], &comma);
315 ap_rputs("<tt> <em>none</em></tt>", r);
317 ap_rputs("</dt>\n", r);
320 static const char *find_more_info(server_rec * s, const char *module_name)
323 info_svr_conf *conf =
324 (info_svr_conf *) ap_get_module_config(s->module_config,
326 info_entry *entry = (info_entry *) conf->more_info->elts;
331 for (i = 0; i < conf->more_info->nelts; i++) {
332 if (!strcmp(module_name, entry->name)) {
340 static int show_server_settings(request_rec * r)
342 server_rec *serv = r->server;
343 int max_daemons, forked, threaded;
345 ap_rputs("<h2><a name=\"server\">Server Settings</a></h2>", r);
347 "<dl><dt><strong>Server Version:</strong> "
348 "<font size=\"+1\"><tt>%s</tt></font></dt>\n",
349 ap_get_server_description());
351 "<dt><strong>Server Built:</strong> "
352 "<font size=\"+1\"><tt>%s</tt></font></dt>\n",
353 ap_get_server_built());
355 "<dt><strong>Apache Portable Runtime Version:</strong> "
356 "<font size=\"+1\"><tt>%s</tt></font></dt>\n",
357 apr_version_string());
358 #if APR_MAJOR_VERSION < 2
360 "<dt><strong>Apache Portable Utility Version:</strong> "
361 "<font size=\"+1\"><tt>%s</tt></font></dt>\n",
362 apu_version_string());
365 "<dt><strong>Module Magic Number:</strong> "
366 "<tt>%d:%d</tt></dt>\n", MODULE_MAGIC_NUMBER_MAJOR,
367 MODULE_MAGIC_NUMBER_MINOR);
369 "<dt><strong>Hostname/port:</strong> "
370 "<tt>%s:%u</tt></dt>\n", ap_get_server_name(r),
371 ap_get_server_port(r));
373 "<dt><strong>Timeouts:</strong> "
374 "<tt>connection: %d "
375 "keep-alive: %d</tt></dt>",
376 (int) (apr_time_sec(serv->timeout)),
377 (int) (apr_time_sec(serv->keep_alive_timeout)));
378 ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons);
379 ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded);
380 ap_mpm_query(AP_MPMQ_IS_FORKED, &forked);
381 ap_rprintf(r, "<dt><strong>MPM Name:</strong> <tt>%s</tt></dt>\n",
384 "<dt><strong>MPM Information:</strong> "
385 "<tt>Max Daemons: %d Threaded: %s Forked: %s</tt></dt>\n",
386 max_daemons, threaded ? "yes" : "no", forked ? "yes" : "no");
388 "<dt><strong>Server Architecture:</strong> "
389 "<tt>%ld-bit</tt></dt>\n", 8 * (long) sizeof(void *));
391 "<dt><strong>Server Root:</strong> "
392 "<tt>%s</tt></dt>\n", ap_server_root);
394 "<dt><strong>Config File:</strong> "
395 "<tt>%s</tt></dt>\n", ap_conftree->filename);
397 ap_rputs("<dt><strong>Server Built With:</strong>\n"
398 "<tt style=\"white-space: pre;\">\n", r);
400 /* TODO: Not all of these defines are getting set like they do in main.c.
401 * Missing some headers?
404 #ifdef BIG_SECURITY_HOLE
405 ap_rputs(" -D BIG_SECURITY_HOLE\n", r);
408 #ifdef SECURITY_HOLE_PASS_AUTHORIZATION
409 ap_rputs(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n", r);
413 ap_rputs(" -D OS=\"" OS "\"\n", r);
417 ap_rputs(" -D HAVE_SHMGET\n", r);
420 #if APR_FILE_BASED_SHM
421 ap_rputs(" -D APR_FILE_BASED_SHM\n", r);
425 ap_rputs(" -D APR_HAS_SENDFILE\n", r);
429 ap_rputs(" -D APR_HAS_MMAP\n", r);
433 ap_rputs(" -D NO_WRITEV\n", r);
437 ap_rputs(" -D NO_LINGCLOSE\n", r);
441 ap_rputs(" -D APR_HAVE_IPV6 (IPv4-mapped addresses ", r);
442 #ifdef AP_ENABLE_V4_MAPPED
443 ap_rputs("enabled)\n", r);
445 ap_rputs("disabled)\n", r);
449 #if APR_USE_FLOCK_SERIALIZE
450 ap_rputs(" -D APR_USE_FLOCK_SERIALIZE\n", r);
453 #if APR_USE_SYSVSEM_SERIALIZE
454 ap_rputs(" -D APR_USE_SYSVSEM_SERIALIZE\n", r);
457 #if APR_USE_POSIXSEM_SERIALIZE
458 ap_rputs(" -D APR_USE_POSIXSEM_SERIALIZE\n", r);
461 #if APR_USE_FCNTL_SERIALIZE
462 ap_rputs(" -D APR_USE_FCNTL_SERIALIZE\n", r);
465 #if APR_USE_PROC_PTHREAD_SERIALIZE
466 ap_rputs(" -D APR_USE_PROC_PTHREAD_SERIALIZE\n", r);
468 #if APR_PROCESS_LOCK_IS_GLOBAL
469 ap_rputs(" -D APR_PROCESS_LOCK_IS_GLOBAL\n", r);
472 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
473 ap_rputs(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n", r);
476 #if APR_HAS_OTHER_CHILD
477 ap_rputs(" -D APR_HAS_OTHER_CHILD\n", r);
480 #ifdef AP_HAVE_RELIABLE_PIPED_LOGS
481 ap_rputs(" -D AP_HAVE_RELIABLE_PIPED_LOGS\n", r);
485 ap_rputs(" -D BUFFERED_LOGS\n", r);
487 ap_rputs(" -D PIPE_BUF=%ld\n", (long) PIPE_BUF, r);
491 #if APR_CHARSET_EBCDIC
492 ap_rputs(" -D APR_CHARSET_EBCDIC\n", r);
495 #ifdef NEED_HASHBANG_EMUL
496 ap_rputs(" -D NEED_HASHBANG_EMUL\n", r);
500 ap_rputs(" -D SHARED_CORE\n", r);
503 /* This list displays the compiled in default paths: */
505 ap_rputs(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n", r);
509 ap_rputs(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n", r);
512 #if defined(SHARED_CORE) && defined(SHARED_CORE_DIR)
513 ap_rputs(" -D SHARED_CORE_DIR=\"" SHARED_CORE_DIR "\"\n", r);
516 #ifdef DEFAULT_PIDLOG
517 ap_rputs(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n", r);
520 #ifdef DEFAULT_SCOREBOARD
521 ap_rputs(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n", r);
524 #ifdef DEFAULT_LOCKFILE
525 ap_rputs(" -D DEFAULT_LOCKFILE=\"" DEFAULT_LOCKFILE "\"\n", r);
528 #ifdef DEFAULT_ERRORLOG
529 ap_rputs(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n", r);
533 #ifdef AP_TYPES_CONFIG_FILE
534 ap_rputs(" -D AP_TYPES_CONFIG_FILE=\"" AP_TYPES_CONFIG_FILE "\"\n", r);
537 #ifdef SERVER_CONFIG_FILE
538 ap_rputs(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n", r);
540 ap_rputs("</tt></dt>\n", r);
541 ap_rputs("</dl><hr />", r);
545 static int dump_a_hook(request_rec * r, hook_get_t hook_get)
550 apr_array_header_t *hooks = hook_get();
556 if (r->args && strcasecmp(r->args, "hooks") == 0) {
563 elts = (hook_struct_t *) hooks->elts;
565 for (i = 0; i < hooks->nelts; i++) {
567 " %02d <a href=\"%c%s\">%s</a> <br/>",
568 elts[i].nOrder, qs, elts[i].szName, elts[i].szName);
573 static int show_active_hooks(request_rec * r)
576 ap_rputs("<h2><a name=\"startup_hooks\">Startup Hooks</a></h2>\n<dl>", r);
578 for (i = 0; startup_hooks[i].name; i++) {
579 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n",
580 startup_hooks[i].name);
581 dump_a_hook(r, startup_hooks[i].get);
582 ap_rputs("\n </tt>\n</dt>\n", r);
586 ("</dl>\n<hr />\n<h2><a name=\"request_hooks\">Request Hooks</a></h2>\n<dl>",
589 for (i = 0; request_hooks[i].name; i++) {
590 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n",
591 request_hooks[i].name);
592 dump_a_hook(r, request_hooks[i].get);
593 ap_rputs("\n </tt>\n</dt>\n", r);
596 ap_rputs("</dl>\n<hr />\n", r);
601 static int display_info(request_rec * r)
604 server_rec *serv = r->server;
605 const char *more_info;
606 const command_rec *cmd = NULL;
609 if (strcmp(r->handler, "server-info"))
612 r->allowed |= (AP_METHOD_BIT << M_GET);
613 if (r->method_number != M_GET)
616 ap_set_content_type(r, "text/html; charset=ISO-8859-1");
618 ap_rputs(DOCTYPE_XHTML_1_0T
619 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
621 " <title>Server Information</title>\n" "</head>\n", r);
622 ap_rputs("<body><h1 style=\"text-align: center\">"
623 "Apache Server Information</h1>\n", r);
624 if (!r->args || strcasecmp(r->args, "list")) {
626 ap_rputs("<dl><dt><tt>Subpages:<br />", r);
627 ap_rputs("<a href=\"?config\">Configuration Files</a>, "
628 "<a href=\"?server\">Server Settings</a>, "
629 "<a href=\"?list\">Module List</a>, "
630 "<a href=\"?hooks\">Active Hooks</a>", r);
631 ap_rputs("</tt></dt></dl><hr />", r);
633 ap_rputs("<dl><dt><tt>Sections:<br />", r);
634 ap_rputs("<a href=\"#server\">Server Settings</a>, "
635 "<a href=\"#startup_hooks\">Startup Hooks</a>, "
636 "<a href=\"#request_hooks\">Request Hooks</a>", r);
637 ap_rputs("</tt></dt></dl><hr />", r);
639 ap_rputs("<dl><dt><tt>Loaded Modules: <br />", r);
640 /* TODO: Sort by Alpha */
641 for (modp = ap_top_module; modp; modp = modp->next) {
642 ap_rprintf(r, "<a href=\"#%s\">%s</a>", modp->name,
648 ap_rputs("</tt></dt></dl><hr />", r);
651 if (!r->args || !strcasecmp(r->args, "server")) {
652 show_server_settings(r);
655 if (!r->args || !strcasecmp(r->args, "hooks")) {
656 show_active_hooks(r);
659 if (r->args && 0 == strcasecmp(r->args, "config")) {
660 ap_rputs("<dl><dt><strong>Configuration:</strong>\n", r);
661 mod_info_module_cmds(r, NULL, ap_conftree, 0, 0);
662 ap_rputs("</dl><hr />", r);
665 for (modp = ap_top_module; modp; modp = modp->next) {
666 if (!r->args || !strcasecmp(modp->name, r->args)) {
668 "<dl><dt><a name=\"%s\"><strong>Module Name:</strong></a> "
669 "<font size=\"+1\"><tt><a href=\"?%s\">%s</a></tt></font></dt>\n",
670 modp->name, modp->name, modp->name);
671 ap_rputs("<dt><strong>Content handlers:</strong> ", r);
673 if (module_find_hook(modp, ap_hook_get_handler)) {
674 ap_rputs("<tt> <em>yes</em></tt>", r);
677 ap_rputs("<tt> <em>none</em></tt>", r);
680 ap_rputs("</dt>", r);
682 ("<dt><strong>Configuration Phase Participation:</strong>\n",
684 if (modp->create_dir_config) {
688 ap_rputs("<tt>Create Directory Config</tt>", r);
691 if (modp->merge_dir_config) {
695 ap_rputs("<tt>Merge Directory Configs</tt>", r);
698 if (modp->create_server_config) {
702 ap_rputs("<tt>Create Server Config</tt>", r);
705 if (modp->merge_server_config) {
709 ap_rputs("<tt>Merge Server Configs</tt>", r);
713 ap_rputs("<tt> <em>none</em></tt>", r);
715 ap_rputs("</dt>", r);
717 module_request_hook_participate(r, modp);
722 ("<dt><strong>Module Directives:</strong></dt>",
726 ap_rprintf(r, "<dd><tt>%s%s - <i>",
727 ap_escape_html(r->pool, cmd->name),
728 cmd->name[0] == '<' ? ">" : "");
730 ap_rputs(ap_escape_html(r->pool, cmd->errmsg), r);
732 ap_rputs("</i></tt></dd>\n", r);
740 ("<dt><strong>Current Configuration:</strong></dt>\n",
742 mod_info_module_cmds(r, modp->cmds, ap_conftree, 0,
747 ("<dt><strong>Module Directives:</strong> <tt>none</tt></dt>",
750 more_info = find_more_info(serv, modp->name);
753 ("<dt><strong>Additional Information:</strong>\n</dt><dd>",
755 ap_rputs(more_info, r);
756 ap_rputs("</dd>", r);
758 ap_rputs("</dl><hr />\n", r);
764 if (!modp && r->args && strcasecmp(r->args, "server")) {
765 ap_rputs("<p><b>No such module</b></p>\n", r);
770 ap_rputs("<dl><dt>Server Module List</dt>", r);
771 for (modp = ap_top_module; modp; modp = modp->next) {
773 ap_rputs(modp->name, r);
774 ap_rputs("</dd>", r);
776 ap_rputs("</dl><hr />", r);
778 ap_rputs(ap_psignature("", r), r);
779 ap_rputs("</body></html>\n", r);
780 /* Done, turn off timeout, close file and return */
784 static const char *add_module_info(cmd_parms * cmd, void *dummy,
785 const char *name, const char *info)
787 server_rec *s = cmd->server;
788 info_svr_conf *conf =
789 (info_svr_conf *) ap_get_module_config(s->module_config,
791 info_entry *new = apr_array_push(conf->more_info);
798 static const command_rec info_cmds[] = {
799 AP_INIT_TAKE2("AddModuleInfo", add_module_info, NULL, RSRC_CONF,
800 "a module name and additional information on that module"),
804 static void register_hooks(apr_pool_t * p)
806 ap_hook_handler(display_info, NULL, NULL, APR_HOOK_MIDDLE);
809 module AP_MODULE_DECLARE_DATA info_module = {
810 STANDARD20_MODULE_STUFF,
811 NULL, /* dir config creater */
812 NULL, /* dir merger --- default is to override */
813 create_info_config, /* server config */
814 merge_info_config, /* merge server config */
815 info_cmds, /* command apr_table_t */