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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17/* 18 * Info Module. Display configuration information for the server and 19 * all included modules. 20 * 21 * <Location /server-info> 22 * SetHandler server-info 23 * </Location> 24 * 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 31 * 32 * Original Author: 33 * Rasmus Lerdorf <rasmus vex.net>, May 1996 34 * 35 * Modified By: 36 * Lou Langholtz <ldl usi.utah.edu>, July 1997 37 * 38 * Apache 2.0 Port: 39 * Ryan Morgan <rmorgan covalent.net>, August 2000 40 * 41 */ 42 43 44#include "apr.h" 45#include "apr_strings.h" 46#include "apr_lib.h" 47#include "apr_version.h" 48#include "apu_version.h" 49#define APR_WANT_STRFUNC 50#include "apr_want.h" 51 52#define CORE_PRIVATE 53 54#include "httpd.h" 55#include "http_config.h" 56#include "http_core.h" 57#include "http_log.h" 58#include "http_main.h" 59#include "http_protocol.h" 60#include "http_connection.h" 61#include "http_request.h" 62#include "util_script.h" 63#include "ap_mpm.h" 64 65typedef struct 66{ 67 const char *name; /* matching module name */ 68 const char *info; /* additional info */ 69} info_entry; 70 71typedef struct 72{ 73 apr_array_header_t *more_info; 74} info_svr_conf; 75 76module AP_MODULE_DECLARE_DATA info_module; 77 78static void *create_info_config(apr_pool_t * p, server_rec * s) 79{ 80 info_svr_conf *conf = 81 (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf)); 82 83 conf->more_info = apr_array_make(p, 20, sizeof(info_entry)); 84 return conf; 85} 86 87static void *merge_info_config(apr_pool_t * p, void *basev, void *overridesv) 88{ 89 info_svr_conf *new = 90 (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf)); 91 info_svr_conf *base = (info_svr_conf *) basev; 92 info_svr_conf *overrides = (info_svr_conf *) overridesv; 93 94 new->more_info = 95 apr_array_append(p, overrides->more_info, base->more_info); 96 return new; 97} 98 99static void put_int_flush_right(request_rec * r, int i, int field) 100{ 101 if (field > 1 || i > 9) 102 put_int_flush_right(r, i / 10, field - 1); 103 if (i) 104 ap_rputc('0' + i % 10, r); 105 else 106 ap_rputs(" ", r); 107} 108 109static void mod_info_indent(request_rec * r, int nest, 110 const char *thisfn, int linenum) 111{ 112 int i; 113 const char *prevfn = 114 ap_get_module_config(r->request_config, &info_module); 115 if (thisfn == NULL) 116 thisfn = "*UNKNOWN*"; 117 if (prevfn == NULL || 0 != strcmp(prevfn, thisfn)) { 118 thisfn = ap_escape_html(r->pool, thisfn); 119 ap_rprintf(r, "<dd><tt><strong>In file: %s</strong></tt></dd>\n", 120 thisfn); 121 ap_set_module_config(r->request_config, &info_module, 122 (void *) thisfn); 123 } 124 125 ap_rputs("<dd><tt>", r); 126 put_int_flush_right(r, linenum > 0 ? linenum : 0, 4); 127 ap_rputs(": ", r); 128 129 for (i = 1; i <= nest; ++i) { 130 ap_rputs(" ", r); 131 } 132} 133 134static void mod_info_show_cmd(request_rec * r, const ap_directive_t * dir, 135 int nest) 136{ 137 mod_info_indent(r, nest, dir->filename, dir->line_num); 138 ap_rprintf(r, "%s <i>%s</i></tt></dd>\n", 139 ap_escape_html(r->pool, dir->directive), 140 ap_escape_html(r->pool, dir->args)); 141} 142 143static void mod_info_show_open(request_rec * r, const ap_directive_t * dir, 144 int nest) 145{ 146 mod_info_indent(r, nest, dir->filename, dir->line_num); 147 ap_rprintf(r, "%s %s</tt></dd>\n", 148 ap_escape_html(r->pool, dir->directive), 149 ap_escape_html(r->pool, dir->args)); 150} 151 152static void mod_info_show_close(request_rec * r, const ap_directive_t * dir, 153 int nest) 154{ 155 const char *dirname = dir->directive; 156 mod_info_indent(r, nest, dir->filename, 0); 157 if (*dirname == '<') { 158 ap_rprintf(r, "</%s></tt></dd>", 159 ap_escape_html(r->pool, dirname + 1)); 160 } 161 else { 162 ap_rprintf(r, "/%s</tt></dd>", ap_escape_html(r->pool, dirname)); 163 } 164} 165 166static int mod_info_has_cmd(const command_rec * cmds, ap_directive_t * dir) 167{ 168 const command_rec *cmd; 169 if (cmds == NULL) 170 return 1; 171 for (cmd = cmds; cmd->name; ++cmd) { 172 if (strcasecmp(cmd->name, dir->directive) == 0) 173 return 1; 174 } 175 return 0; 176} 177 178static void mod_info_show_parents(request_rec * r, ap_directive_t * node, 179 int from, int to) 180{ 181 if (from < to) 182 mod_info_show_parents(r, node->parent, from, to - 1); 183 mod_info_show_open(r, node, to); 184} 185 186static int mod_info_module_cmds(request_rec * r, const command_rec * cmds, 187 ap_directive_t * node, int from, int level) 188{ 189 int shown = from; 190 ap_directive_t *dir; 191 if (level == 0) 192 ap_set_module_config(r->request_config, &info_module, NULL); 193 for (dir = node; dir; dir = dir->next) { 194 if (dir->first_child != NULL) { 195 if (level < mod_info_module_cmds(r, cmds, dir->first_child, 196 shown, level + 1)) { 197 shown = level; 198 mod_info_show_close(r, dir, level); 199 } 200 } 201 else if (mod_info_has_cmd(cmds, dir)) { 202 if (shown < level) { 203 mod_info_show_parents(r, dir->parent, shown, level - 1); 204 shown = level; 205 } 206 mod_info_show_cmd(r, dir, level); 207 } 208 } 209 return shown; 210} 211 212typedef struct 213{ /*XXX: should get something from apr_hooks.h instead */ 214 void (*pFunc) (void); /* just to get the right size */ 215 const char *szName; 216 const char *const *aszPredecessors; 217 const char *const *aszSuccessors; 218 int nOrder; 219} hook_struct_t; 220 221/* 222 * hook_get_t is a pointer to a function that takes void as an argument and 223 * returns a pointer to an apr_array_header_t. The nasty WIN32 ifdef 224 * is required to account for the fact that the ap_hook* calls all use 225 * STDCALL calling convention. 226 */ 227typedef apr_array_header_t *( 228#ifdef WIN32 229 __stdcall 230#endif 231 * hook_get_t) (void); 232 233typedef struct 234{ 235 const char *name; 236 hook_get_t get; 237} hook_lookup_t; 238 239static hook_lookup_t startup_hooks[] = { 240 {"Pre-Config", ap_hook_get_pre_config}, 241 {"Test Configuration", ap_hook_get_test_config}, 242 {"Post Configuration", ap_hook_get_post_config}, 243 {"Open Logs", ap_hook_get_open_logs}, 244 {"Child Init", ap_hook_get_child_init}, 245 {NULL}, 246}; 247 248static hook_lookup_t request_hooks[] = { 249 {"Pre-Connection", ap_hook_get_pre_connection}, 250 {"Create Connection", ap_hook_get_create_connection}, 251 {"Process Connection", ap_hook_get_process_connection}, 252 {"Create Request", ap_hook_get_create_request}, 253 {"Post-Read Request", ap_hook_get_post_read_request}, 254 {"Header Parse", ap_hook_get_header_parser}, 255 {"HTTP Scheme", ap_hook_get_http_scheme}, 256 {"Default Port", ap_hook_get_default_port}, 257 {"Quick Handler", ap_hook_get_quick_handler}, 258 {"Translate Name", ap_hook_get_translate_name}, 259 {"Map to Storage", ap_hook_get_map_to_storage}, 260 {"Check Access", ap_hook_get_access_checker}, 261 {"Verify User ID", ap_hook_get_check_user_id}, 262 {"Verify User Access", ap_hook_get_auth_checker}, 263 {"Check Type", ap_hook_get_type_checker}, 264 {"Fixups", ap_hook_get_fixups}, 265 {"Insert Filters", ap_hook_get_insert_filter}, 266 {"Content Handlers", ap_hook_get_handler}, 267 {"Logging", ap_hook_get_log_transaction}, 268 {"Insert Errors", ap_hook_get_insert_error_filter}, 269 {NULL}, 270}; 271 272static int module_find_hook(module * modp, hook_get_t hook_get) 273{ 274 int i; 275 apr_array_header_t *hooks = hook_get(); 276 hook_struct_t *elts; 277 278 if (!hooks) { 279 return 0; 280 } 281 282 elts = (hook_struct_t *) hooks->elts; 283 284 for (i = 0; i < hooks->nelts; i++) { 285 if (strcmp(elts[i].szName, modp->name) == 0) { 286 return 1; 287 } 288 } 289 290 return 0; 291} 292 293static void module_participate(request_rec * r, 294 module * modp, 295 hook_lookup_t * lookup, int *comma) 296{ 297 if (module_find_hook(modp, lookup->get)) { 298 if (*comma) { 299 ap_rputs(", ", r); 300 } 301 ap_rvputs(r, "<tt>", lookup->name, "</tt>", NULL); 302 *comma = 1; 303 } 304} 305 306static void module_request_hook_participate(request_rec * r, module * modp) 307{ 308 int i, comma = 0; 309 310 ap_rputs("<dt><strong>Request Phase Participation:</strong>\n", r); 311 312 for (i = 0; request_hooks[i].name; i++) { 313 module_participate(r, modp, &request_hooks[i], &comma); 314 } 315 316 if (!comma) { 317 ap_rputs("<tt> <em>none</em></tt>", r); 318 } 319 ap_rputs("</dt>\n", r); 320} 321 322static const char *find_more_info(server_rec * s, const char *module_name) 323{ 324 int i; 325 info_svr_conf *conf = 326 (info_svr_conf *) ap_get_module_config(s->module_config, 327 &info_module); 328 info_entry *entry = (info_entry *) conf->more_info->elts; 329 330 if (!module_name) { 331 return 0; 332 } 333 for (i = 0; i < conf->more_info->nelts; i++) { 334 if (!strcmp(module_name, entry->name)) { 335 return entry->info; 336 } 337 entry++; 338 } 339 return 0; 340} 341 342static int show_server_settings(request_rec * r) 343{ 344 server_rec *serv = r->server; 345 int max_daemons, forked, threaded; 346 347 ap_rputs("<h2><a name=\"server\">Server Settings</a></h2>", r); 348 ap_rprintf(r, 349 "<dl><dt><strong>Server Version:</strong> " 350 "<font size=\"+1\"><tt>%s</tt></font></dt>\n", 351 ap_get_server_description()); 352 ap_rprintf(r, 353 "<dt><strong>Server Built:</strong> " 354 "<font size=\"+1\"><tt>%s</tt></font></dt>\n", 355 ap_get_server_built()); 356 ap_rprintf(r, 357 "<dt><strong>Server loaded APR Version:</strong> " 358 "<tt>%s</tt></dt>\n", apr_version_string()); 359 ap_rprintf(r, 360 "<dt><strong>Compiled with APR Version:</strong> " 361 "<tt>%s</tt></dt>\n", APR_VERSION_STRING); 362 ap_rprintf(r, 363 "<dt><strong>Server loaded APU Version:</strong> " 364 "<tt>%s</tt></dt>\n", apu_version_string()); 365 ap_rprintf(r, 366 "<dt><strong>Compiled with APU Version:</strong> " 367 "<tt>%s</tt></dt>\n", APU_VERSION_STRING); 368 ap_rprintf(r, 369 "<dt><strong>Module Magic Number:</strong> " 370 "<tt>%d:%d</tt></dt>\n", MODULE_MAGIC_NUMBER_MAJOR, 371 MODULE_MAGIC_NUMBER_MINOR); 372 ap_rprintf(r, 373 "<dt><strong>Hostname/port:</strong> " 374 "<tt>%s:%u</tt></dt>\n", 375 ap_escape_html(r->pool, ap_get_server_name(r)), 376 ap_get_server_port(r)); 377 ap_rprintf(r, 378 "<dt><strong>Timeouts:</strong> " 379 "<tt>connection: %d " 380 "keep-alive: %d</tt></dt>", 381 (int) (apr_time_sec(serv->timeout)), 382 (int) (apr_time_sec(serv->keep_alive_timeout))); 383 ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons); 384 ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded); 385 ap_mpm_query(AP_MPMQ_IS_FORKED, &forked); 386 ap_rprintf(r, "<dt><strong>MPM Name:</strong> <tt>%s</tt></dt>\n", 387 ap_show_mpm()); 388 ap_rprintf(r, 389 "<dt><strong>MPM Information:</strong> " 390 "<tt>Max Daemons: %d Threaded: %s Forked: %s</tt></dt>\n", 391 max_daemons, threaded ? "yes" : "no", forked ? "yes" : "no"); 392 ap_rprintf(r, 393 "<dt><strong>Server Architecture:</strong> " 394 "<tt>%ld-bit</tt></dt>\n", 8 * (long) sizeof(void *)); 395 ap_rprintf(r, 396 "<dt><strong>Server Root:</strong> " 397 "<tt>%s</tt></dt>\n", ap_server_root); 398 ap_rprintf(r, 399 "<dt><strong>Config File:</strong> " 400 "<tt>%s</tt></dt>\n", ap_conftree->filename); 401 402 ap_rputs("<dt><strong>Server Built With:</strong>\n" 403 "<tt style=\"white-space: pre;\">\n", r); 404 405 /* TODO: Not all of these defines are getting set like they do in main.c. 406 * Missing some headers? 407 */ 408 409#ifdef BIG_SECURITY_HOLE 410 ap_rputs(" -D BIG_SECURITY_HOLE\n", r); 411#endif 412 413#ifdef SECURITY_HOLE_PASS_AUTHORIZATION 414 ap_rputs(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n", r); 415#endif 416 417#ifdef OS 418 ap_rputs(" -D OS=\"" OS "\"\n", r); 419#endif 420 421#ifdef APACHE_MPM_DIR 422 ap_rputs(" -D APACHE_MPM_DIR=\"" APACHE_MPM_DIR "\"\n", r); 423#endif 424 425#ifdef HAVE_SHMGET 426 ap_rputs(" -D HAVE_SHMGET\n", r); 427#endif 428 429#if APR_FILE_BASED_SHM 430 ap_rputs(" -D APR_FILE_BASED_SHM\n", r); 431#endif 432 433#if APR_HAS_SENDFILE 434 ap_rputs(" -D APR_HAS_SENDFILE\n", r); 435#endif 436 437#if APR_HAS_MMAP 438 ap_rputs(" -D APR_HAS_MMAP\n", r); 439#endif 440 441#ifdef NO_WRITEV 442 ap_rputs(" -D NO_WRITEV\n", r); 443#endif 444 445#ifdef NO_LINGCLOSE 446 ap_rputs(" -D NO_LINGCLOSE\n", r); 447#endif 448 449#if APR_HAVE_IPV6 450 ap_rputs(" -D APR_HAVE_IPV6 (IPv4-mapped addresses ", r); 451#ifdef AP_ENABLE_V4_MAPPED 452 ap_rputs("enabled)\n", r); 453#else 454 ap_rputs("disabled)\n", r); 455#endif 456#endif 457 458#if APR_USE_FLOCK_SERIALIZE 459 ap_rputs(" -D APR_USE_FLOCK_SERIALIZE\n", r); 460#endif 461 462#if APR_USE_SYSVSEM_SERIALIZE 463 ap_rputs(" -D APR_USE_SYSVSEM_SERIALIZE\n", r); 464#endif 465 466#if APR_USE_POSIXSEM_SERIALIZE 467 ap_rputs(" -D APR_USE_POSIXSEM_SERIALIZE\n", r); 468#endif 469 470#if APR_USE_FCNTL_SERIALIZE 471 ap_rputs(" -D APR_USE_FCNTL_SERIALIZE\n", r); 472#endif 473 474#if APR_USE_PROC_PTHREAD_SERIALIZE 475 ap_rputs(" -D APR_USE_PROC_PTHREAD_SERIALIZE\n", r); 476#endif 477#if APR_PROCESS_LOCK_IS_GLOBAL 478 ap_rputs(" -D APR_PROCESS_LOCK_IS_GLOBAL\n", r); 479#endif 480 481#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT 482 ap_rputs(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n", r); 483#endif 484 485#if APR_HAS_OTHER_CHILD 486 ap_rputs(" -D APR_HAS_OTHER_CHILD\n", r); 487#endif 488 489#ifdef AP_HAVE_RELIABLE_PIPED_LOGS 490 ap_rputs(" -D AP_HAVE_RELIABLE_PIPED_LOGS\n", r); 491#endif 492 493#ifdef BUFFERED_LOGS 494 ap_rputs(" -D BUFFERED_LOGS\n", r); 495#ifdef PIPE_BUF 496 ap_rputs(" -D PIPE_BUF=%ld\n", (long) PIPE_BUF, r); 497#endif 498#endif 499 500#if APR_CHARSET_EBCDIC 501 ap_rputs(" -D APR_CHARSET_EBCDIC\n", r); 502#endif 503 504#ifdef NEED_HASHBANG_EMUL 505 ap_rputs(" -D NEED_HASHBANG_EMUL\n", r); 506#endif 507 508#ifdef SHARED_CORE 509 ap_rputs(" -D SHARED_CORE\n", r); 510#endif 511 512/* This list displays the compiled in default paths: */ 513#ifdef HTTPD_ROOT 514 ap_rputs(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n", r); 515#endif 516 517#ifdef SUEXEC_BIN 518 ap_rputs(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n", r); 519#endif 520 521#if defined(SHARED_CORE) && defined(SHARED_CORE_DIR) 522 ap_rputs(" -D SHARED_CORE_DIR=\"" SHARED_CORE_DIR "\"\n", r); 523#endif 524 525#ifdef DEFAULT_PIDLOG 526 ap_rputs(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n", r); 527#endif 528 529#ifdef DEFAULT_SCOREBOARD 530 ap_rputs(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n", r); 531#endif 532 533#ifdef DEFAULT_LOCKFILE 534 ap_rputs(" -D DEFAULT_LOCKFILE=\"" DEFAULT_LOCKFILE "\"\n", r); 535#endif 536 537#ifdef DEFAULT_ERRORLOG 538 ap_rputs(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n", r); 539#endif 540 541 542#ifdef AP_TYPES_CONFIG_FILE 543 ap_rputs(" -D AP_TYPES_CONFIG_FILE=\"" AP_TYPES_CONFIG_FILE "\"\n", r); 544#endif 545 546#ifdef SERVER_CONFIG_FILE 547 ap_rputs(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n", r); 548#endif 549 ap_rputs("</tt></dt>\n", r); 550 ap_rputs("</dl><hr />", r); 551 return 0; 552} 553 554static int dump_a_hook(request_rec * r, hook_get_t hook_get) 555{ 556 int i; 557 char qs; 558 hook_struct_t *elts; 559 apr_array_header_t *hooks = hook_get(); 560 561 if (!hooks) { 562 return 0; 563 } 564 565 if (r->args && strcasecmp(r->args, "hooks") == 0) { 566 qs = '?'; 567 } 568 else { 569 qs = '#'; 570 } 571 572 elts = (hook_struct_t *) hooks->elts; 573 574 for (i = 0; i < hooks->nelts; i++) { 575 ap_rprintf(r, 576 " %02d <a href=\"%c%s\">%s</a> <br/>", 577 elts[i].nOrder, qs, elts[i].szName, elts[i].szName); 578 } 579 return 0; 580} 581 582static int show_active_hooks(request_rec * r) 583{ 584 int i; 585 ap_rputs("<h2><a name=\"startup_hooks\">Startup Hooks</a></h2>\n<dl>", r); 586 587 for (i = 0; startup_hooks[i].name; i++) { 588 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n", 589 startup_hooks[i].name); 590 dump_a_hook(r, startup_hooks[i].get); 591 ap_rputs("\n </tt>\n</dt>\n", r); 592 } 593 594 ap_rputs 595 ("</dl>\n<hr />\n<h2><a name=\"request_hooks\">Request Hooks</a></h2>\n<dl>", 596 r); 597 598 for (i = 0; request_hooks[i].name; i++) { 599 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n", 600 request_hooks[i].name); 601 dump_a_hook(r, request_hooks[i].get); 602 ap_rputs("\n </tt>\n</dt>\n", r); 603 } 604 605 ap_rputs("</dl>\n<hr />\n", r); 606 607 return 0; 608} 609 610static int display_info(request_rec * r) 611{ 612 module *modp = NULL; 613 server_rec *serv = r->server; 614 const char *more_info; 615 const command_rec *cmd = NULL; 616 int comma = 0; 617 618 if (strcmp(r->handler, "server-info")) 619 return DECLINED; 620 621 r->allowed |= (AP_METHOD_BIT << M_GET); 622 if (r->method_number != M_GET) 623 return DECLINED; 624 625 ap_set_content_type(r, "text/html; charset=ISO-8859-1"); 626 627 ap_rputs(DOCTYPE_XHTML_1_0T 628 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" 629 "<head>\n" 630 " <title>Server Information</title>\n" "</head>\n", r); 631 ap_rputs("<body><h1 style=\"text-align: center\">" 632 "Apache Server Information</h1>\n", r); 633 if (!r->args || strcasecmp(r->args, "list")) { 634 if (!r->args) { 635 ap_rputs("<dl><dt><tt>Subpages:<br />", r); 636 ap_rputs("<a href=\"?config\">Configuration Files</a>, " 637 "<a href=\"?server\">Server Settings</a>, " 638 "<a href=\"?list\">Module List</a>, " 639 "<a href=\"?hooks\">Active Hooks</a>", r); 640 ap_rputs("</tt></dt></dl><hr />", r); 641 642 ap_rputs("<dl><dt><tt>Sections:<br />", r); 643 ap_rputs("<a href=\"#server\">Server Settings</a>, " 644 "<a href=\"#startup_hooks\">Startup Hooks</a>, " 645 "<a href=\"#request_hooks\">Request Hooks</a>", r); 646 ap_rputs("</tt></dt></dl><hr />", r); 647 648 ap_rputs("<dl><dt><tt>Loaded Modules: <br />", r); 649 /* TODO: Sort by Alpha */ 650 for (modp = ap_top_module; modp; modp = modp->next) { 651 ap_rprintf(r, "<a href=\"#%s\">%s</a>", modp->name, 652 modp->name); 653 if (modp->next) { 654 ap_rputs(", ", r); 655 } 656 } 657 ap_rputs("</tt></dt></dl><hr />", r); 658 } 659 660 if (!r->args || !strcasecmp(r->args, "server")) { 661 show_server_settings(r); 662 } 663 664 if (!r->args || !strcasecmp(r->args, "hooks")) { 665 show_active_hooks(r); 666 } 667 668 if (r->args && 0 == strcasecmp(r->args, "config")) { 669 ap_rputs("<dl><dt><strong>Configuration:</strong>\n", r); 670 mod_info_module_cmds(r, NULL, ap_conftree, 0, 0); 671 ap_rputs("</dl><hr />", r); 672 } 673 else { 674 for (modp = ap_top_module; modp; modp = modp->next) { 675 if (!r->args || !strcasecmp(modp->name, r->args)) { 676 ap_rprintf(r, 677 "<dl><dt><a name=\"%s\"><strong>Module Name:</strong></a> " 678 "<font size=\"+1\"><tt><a href=\"?%s\">%s</a></tt></font></dt>\n", 679 modp->name, modp->name, modp->name); 680 ap_rputs("<dt><strong>Content handlers:</strong> ", r); 681 682 if (module_find_hook(modp, ap_hook_get_handler)) { 683 ap_rputs("<tt> <em>yes</em></tt>", r); 684 } 685 else { 686 ap_rputs("<tt> <em>none</em></tt>", r); 687 } 688 689 ap_rputs("</dt>", r); 690 ap_rputs 691 ("<dt><strong>Configuration Phase Participation:</strong>\n", 692 r); 693 if (modp->create_dir_config) { 694 if (comma) { 695 ap_rputs(", ", r); 696 } 697 ap_rputs("<tt>Create Directory Config</tt>", r); 698 comma = 1; 699 } 700 if (modp->merge_dir_config) { 701 if (comma) { 702 ap_rputs(", ", r); 703 } 704 ap_rputs("<tt>Merge Directory Configs</tt>", r); 705 comma = 1; 706 } 707 if (modp->create_server_config) { 708 if (comma) { 709 ap_rputs(", ", r); 710 } 711 ap_rputs("<tt>Create Server Config</tt>", r); 712 comma = 1; 713 } 714 if (modp->merge_server_config) { 715 if (comma) { 716 ap_rputs(", ", r); 717 } 718 ap_rputs("<tt>Merge Server Configs</tt>", r); 719 comma = 1; 720 } 721 if (!comma) 722 ap_rputs("<tt> <em>none</em></tt>", r); 723 comma = 0; 724 ap_rputs("</dt>", r); 725 726 module_request_hook_participate(r, modp); 727 728 cmd = modp->cmds; 729 if (cmd) { 730 ap_rputs 731 ("<dt><strong>Module Directives:</strong></dt>", 732 r); 733 while (cmd) { 734 if (cmd->name) { 735 ap_rprintf(r, "<dd><tt>%s%s - <i>", 736 ap_escape_html(r->pool, cmd->name), 737 cmd->name[0] == '<' ? ">" : ""); 738 if (cmd->errmsg) { 739 ap_rputs(ap_escape_html(r->pool, cmd->errmsg), r); 740 } 741 ap_rputs("</i></tt></dd>\n", r); 742 } 743 else { 744 break; 745 } 746 cmd++; 747 } 748 ap_rputs 749 ("<dt><strong>Current Configuration:</strong></dt>\n", 750 r); 751 mod_info_module_cmds(r, modp->cmds, ap_conftree, 0, 752 0); 753 } 754 else { 755 ap_rputs 756 ("<dt><strong>Module Directives:</strong> <tt>none</tt></dt>", 757 r); 758 } 759 more_info = find_more_info(serv, modp->name); 760 if (more_info) { 761 ap_rputs 762 ("<dt><strong>Additional Information:</strong>\n</dt><dd>", 763 r); 764 ap_rputs(more_info, r); 765 ap_rputs("</dd>", r); 766 } 767 ap_rputs("</dl><hr />\n", r); 768 if (r->args) { 769 break; 770 } 771 } 772 } 773 if (!modp && r->args && strcasecmp(r->args, "server")) { 774 ap_rputs("<p><b>No such module</b></p>\n", r); 775 } 776 } 777 } 778 else { 779 ap_rputs("<dl><dt>Server Module List</dt>", r); 780 for (modp = ap_top_module; modp; modp = modp->next) { 781 ap_rputs("<dd>", r); 782 ap_rputs(modp->name, r); 783 ap_rputs("</dd>", r); 784 } 785 ap_rputs("</dl><hr />", r); 786 } 787 ap_rputs(ap_psignature("", r), r); 788 ap_rputs("</body></html>\n", r); 789 /* Done, turn off timeout, close file and return */ 790 return 0; 791} 792 793static const char *add_module_info(cmd_parms * cmd, void *dummy, 794 const char *name, const char *info) 795{ 796 server_rec *s = cmd->server; 797 info_svr_conf *conf = 798 (info_svr_conf *) ap_get_module_config(s->module_config, 799 &info_module); 800 info_entry *new = apr_array_push(conf->more_info); 801 802 new->name = name; 803 new->info = info; 804 return NULL; 805} 806 807static const command_rec info_cmds[] = { 808 AP_INIT_TAKE2("AddModuleInfo", add_module_info, NULL, RSRC_CONF, 809 "a module name and additional information on that module"), 810 {NULL} 811}; 812 813static void register_hooks(apr_pool_t * p) 814{ 815 ap_hook_handler(display_info, NULL, NULL, APR_HOOK_MIDDLE); 816} 817 818module AP_MODULE_DECLARE_DATA info_module = { 819 STANDARD20_MODULE_STUFF, 820 NULL, /* dir config creater */ 821 NULL, /* dir merger --- default is to override */ 822 create_info_config, /* server config */ 823 merge_info_config, /* merge server config */ 824 info_cmds, /* command apr_table_t */ 825 register_hooks 826}; 827