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#if APR_MAJOR_VERSION < 2 49#include "apu_version.h" 50#endif 51#define APR_WANT_STRFUNC 52#include "apr_want.h" 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#include "mpm_common.h" 65#include "ap_provider.h" 66#include <stdio.h> 67#include <stdlib.h> 68 69typedef struct 70{ 71 const char *name; /* matching module name */ 72 const char *info; /* additional info */ 73} info_entry; 74 75typedef struct 76{ 77 apr_array_header_t *more_info; 78} info_svr_conf; 79 80module AP_MODULE_DECLARE_DATA info_module; 81 82/* current file name when doing -DDUMP_CONFIG */ 83const char *dump_config_fn_info; 84/* file handle when doing -DDUMP_CONFIG */ 85apr_file_t *out = NULL; 86 87static void *create_info_config(apr_pool_t * p, server_rec * s) 88{ 89 info_svr_conf *conf = 90 (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf)); 91 92 conf->more_info = apr_array_make(p, 20, sizeof(info_entry)); 93 return conf; 94} 95 96static void *merge_info_config(apr_pool_t * p, void *basev, void *overridesv) 97{ 98 info_svr_conf *new = 99 (info_svr_conf *) apr_pcalloc(p, sizeof(info_svr_conf)); 100 info_svr_conf *base = (info_svr_conf *) basev; 101 info_svr_conf *overrides = (info_svr_conf *) overridesv; 102 103 new->more_info = 104 apr_array_append(p, overrides->more_info, base->more_info); 105 return new; 106} 107 108static void put_int_flush_right(request_rec * r, int i, int field) 109{ 110 if (field > 1 || i > 9) 111 put_int_flush_right(r, i / 10, field - 1); 112 if (i) { 113 if (r) 114 ap_rputc('0' + i % 10, r); 115 else 116 apr_file_putc((char)('0' + i % 10), out); 117 } 118 else { 119 if (r) 120 ap_rputs(" ", r); 121 else 122 apr_file_printf(out, " "); 123 } 124} 125 126static void set_fn_info(request_rec *r, const char *name) 127{ 128 if (r) 129 ap_set_module_config(r->request_config, &info_module, (void *)name); 130 else 131 dump_config_fn_info = name; 132} 133 134static const char *get_fn_info(request_rec *r) 135{ 136 if (r) 137 return ap_get_module_config(r->request_config, &info_module); 138 else 139 return dump_config_fn_info; 140} 141 142 143static void mod_info_indent(request_rec * r, int nest, 144 const char *thisfn, int linenum) 145{ 146 int i; 147 const char *prevfn = get_fn_info(r); 148 if (thisfn == NULL) 149 thisfn = "*UNKNOWN*"; 150 if (prevfn == NULL || 0 != strcmp(prevfn, thisfn)) { 151 if (r) { 152 thisfn = ap_escape_html(r->pool, thisfn); 153 ap_rprintf(r, "<dd><tt><strong>In file: %s</strong></tt></dd>\n", 154 thisfn); 155 } 156 else { 157 apr_file_printf(out, "# In file: %s\n", thisfn); 158 } 159 set_fn_info(r, thisfn); 160 } 161 162 if (r) { 163 ap_rputs("<dd><tt>", r); 164 put_int_flush_right(r, linenum > 0 ? linenum : 0, 4); 165 ap_rputs(": ", r); 166 } 167 else if (linenum > 0) { 168 for (i = 1; i <= nest; ++i) 169 apr_file_printf(out, " "); 170 apr_file_putc('#', out); 171 put_int_flush_right(r, linenum, 4); 172 apr_file_printf(out, ":\n"); 173 } 174 175 for (i = 1; i <= nest; ++i) { 176 if (r) 177 ap_rputs(" ", r); 178 else 179 apr_file_printf(out, " "); 180 } 181} 182 183static void mod_info_show_cmd(request_rec * r, const ap_directive_t * dir, 184 int nest) 185{ 186 mod_info_indent(r, nest, dir->filename, dir->line_num); 187 if (r) 188 ap_rprintf(r, "%s <i>%s</i></tt></dd>\n", 189 ap_escape_html(r->pool, dir->directive), 190 ap_escape_html(r->pool, dir->args)); 191 else 192 apr_file_printf(out, "%s %s\n", dir->directive, dir->args); 193} 194 195static void mod_info_show_open(request_rec * r, const ap_directive_t * dir, 196 int nest) 197{ 198 mod_info_indent(r, nest, dir->filename, dir->line_num); 199 if (r) 200 ap_rprintf(r, "%s %s</tt></dd>\n", 201 ap_escape_html(r->pool, dir->directive), 202 ap_escape_html(r->pool, dir->args)); 203 else 204 apr_file_printf(out, "%s %s\n", dir->directive, dir->args); 205} 206 207static void mod_info_show_close(request_rec * r, const ap_directive_t * dir, 208 int nest) 209{ 210 const char *dirname = dir->directive; 211 mod_info_indent(r, nest, dir->filename, 0); 212 if (*dirname == '<') { 213 if (r) 214 ap_rprintf(r, "</%s></tt></dd>", 215 ap_escape_html(r->pool, dirname + 1)); 216 else 217 apr_file_printf(out, "</%s>\n", dirname + 1); 218 } 219 else { 220 if (r) 221 ap_rprintf(r, "/%s</tt></dd>", ap_escape_html(r->pool, dirname)); 222 else 223 apr_file_printf(out, "/%s\n", dirname); 224 } 225} 226 227static int mod_info_has_cmd(const command_rec * cmds, ap_directive_t * dir) 228{ 229 const command_rec *cmd; 230 if (cmds == NULL) 231 return 1; 232 for (cmd = cmds; cmd->name; ++cmd) { 233 if (strcasecmp(cmd->name, dir->directive) == 0) 234 return 1; 235 } 236 return 0; 237} 238 239static void mod_info_show_parents(request_rec * r, ap_directive_t * node, 240 int from, int to) 241{ 242 if (from < to) 243 mod_info_show_parents(r, node->parent, from, to - 1); 244 mod_info_show_open(r, node, to); 245} 246 247static int mod_info_module_cmds(request_rec * r, const command_rec * cmds, 248 ap_directive_t * node, int from, int level) 249{ 250 int shown = from; 251 ap_directive_t *dir; 252 if (level == 0) 253 set_fn_info(r, NULL); 254 for (dir = node; dir; dir = dir->next) { 255 if (dir->first_child != NULL) { 256 if (level < mod_info_module_cmds(r, cmds, dir->first_child, 257 shown, level + 1)) { 258 shown = level; 259 mod_info_show_close(r, dir, level); 260 } 261 } 262 else if (mod_info_has_cmd(cmds, dir)) { 263 if (shown < level) { 264 mod_info_show_parents(r, dir->parent, shown, level - 1); 265 shown = level; 266 } 267 mod_info_show_cmd(r, dir, level); 268 } 269 } 270 return shown; 271} 272 273typedef struct 274{ /*XXX: should get something from apr_hooks.h instead */ 275 void (*pFunc) (void); /* just to get the right size */ 276 const char *szName; 277 const char *const *aszPredecessors; 278 const char *const *aszSuccessors; 279 int nOrder; 280} hook_struct_t; 281 282/* 283 * hook_get_t is a pointer to a function that takes void as an argument and 284 * returns a pointer to an apr_array_header_t. The nasty WIN32 ifdef 285 * is required to account for the fact that the ap_hook* calls all use 286 * STDCALL calling convention. 287 */ 288typedef apr_array_header_t *( 289#ifdef WIN32 290 __stdcall 291#endif 292 * hook_get_t) (void); 293 294typedef struct 295{ 296 const char *name; 297 hook_get_t get; 298} hook_lookup_t; 299 300static hook_lookup_t startup_hooks[] = { 301 {"Pre-Config", ap_hook_get_pre_config}, 302 {"Check Configuration", ap_hook_get_check_config}, 303 {"Test Configuration", ap_hook_get_test_config}, 304 {"Post Configuration", ap_hook_get_post_config}, 305 {"Open Logs", ap_hook_get_open_logs}, 306 {"Pre-MPM", ap_hook_get_pre_mpm}, 307 {"MPM", ap_hook_get_mpm}, 308 {"Drop Privileges", ap_hook_get_drop_privileges}, 309 {"Retrieve Optional Functions", ap_hook_get_optional_fn_retrieve}, 310 {"Child Init", ap_hook_get_child_init}, 311 {NULL}, 312}; 313 314static hook_lookup_t request_hooks[] = { 315 {"Pre-Connection", ap_hook_get_pre_connection}, 316 {"Create Connection", ap_hook_get_create_connection}, 317 {"Process Connection", ap_hook_get_process_connection}, 318 {"Create Request", ap_hook_get_create_request}, 319 {"Pre-Read Request", ap_hook_get_pre_read_request}, 320 {"Post-Read Request", ap_hook_get_post_read_request}, 321 {"Header Parse", ap_hook_get_header_parser}, 322 {"HTTP Scheme", ap_hook_get_http_scheme}, 323 {"Default Port", ap_hook_get_default_port}, 324 {"Quick Handler", ap_hook_get_quick_handler}, 325 {"Translate Name", ap_hook_get_translate_name}, 326 {"Map to Storage", ap_hook_get_map_to_storage}, 327 {"Check Access", ap_hook_get_access_checker_ex}, 328 {"Check Access (legacy)", ap_hook_get_access_checker}, 329 {"Verify User ID", ap_hook_get_check_user_id}, 330 {"Note Authentication Failure", ap_hook_get_note_auth_failure}, 331 {"Verify User Access", ap_hook_get_auth_checker}, 332 {"Check Type", ap_hook_get_type_checker}, 333 {"Fixups", ap_hook_get_fixups}, 334 {"Insert Filters", ap_hook_get_insert_filter}, 335 {"Content Handlers", ap_hook_get_handler}, 336 {"Transaction Logging", ap_hook_get_log_transaction}, 337 {"Insert Errors", ap_hook_get_insert_error_filter}, 338 {"Generate Log ID", ap_hook_get_generate_log_id}, 339 {NULL}, 340}; 341 342static hook_lookup_t other_hooks[] = { 343 {"Monitor", ap_hook_get_monitor}, 344 {"Child Status", ap_hook_get_child_status}, 345 {"End Generation", ap_hook_get_end_generation}, 346 {"Error Logging", ap_hook_get_error_log}, 347 {"Query MPM Attributes", ap_hook_get_mpm_query}, 348 {"Query MPM Name", ap_hook_get_mpm_get_name}, 349 {"Register Timed Callback", ap_hook_get_mpm_register_timed_callback}, 350 {"Extend Expression Parser", ap_hook_get_expr_lookup}, 351 {"Set Management Items", ap_hook_get_get_mgmt_items}, 352#if AP_ENABLE_EXCEPTION_HOOK 353 {"Handle Fatal Exceptions", ap_hook_get_fatal_exception}, 354#endif 355 {NULL}, 356}; 357 358static int module_find_hook(module * modp, hook_get_t hook_get) 359{ 360 int i; 361 apr_array_header_t *hooks = hook_get(); 362 hook_struct_t *elts; 363 364 if (!hooks) { 365 return 0; 366 } 367 368 elts = (hook_struct_t *) hooks->elts; 369 370 for (i = 0; i < hooks->nelts; i++) { 371 if (strcmp(elts[i].szName, modp->name) == 0) { 372 return 1; 373 } 374 } 375 376 return 0; 377} 378 379static void module_participate(request_rec * r, 380 module * modp, 381 hook_lookup_t * lookup, int *comma) 382{ 383 if (module_find_hook(modp, lookup->get)) { 384 if (*comma) { 385 ap_rputs(", ", r); 386 } 387 ap_rvputs(r, "<tt>", lookup->name, "</tt>", NULL); 388 *comma = 1; 389 } 390} 391 392static void module_request_hook_participate(request_rec * r, module * modp) 393{ 394 int i, comma = 0; 395 396 ap_rputs("<dt><strong>Request Phase Participation:</strong>\n", r); 397 398 for (i = 0; request_hooks[i].name; i++) { 399 module_participate(r, modp, &request_hooks[i], &comma); 400 } 401 402 if (!comma) { 403 ap_rputs("<tt> <em>none</em></tt>", r); 404 } 405 ap_rputs("</dt>\n", r); 406} 407 408static const char *find_more_info(server_rec * s, const char *module_name) 409{ 410 int i; 411 info_svr_conf *conf = 412 (info_svr_conf *) ap_get_module_config(s->module_config, 413 &info_module); 414 info_entry *entry = (info_entry *) conf->more_info->elts; 415 416 if (!module_name) { 417 return 0; 418 } 419 for (i = 0; i < conf->more_info->nelts; i++) { 420 if (!strcmp(module_name, entry->name)) { 421 return entry->info; 422 } 423 entry++; 424 } 425 return 0; 426} 427 428static int show_server_settings(request_rec * r) 429{ 430 server_rec *serv = r->server; 431 int max_daemons, forked, threaded; 432 433 ap_rputs("<h2><a name=\"server\">Server Settings</a></h2>", r); 434 ap_rprintf(r, 435 "<dl><dt><strong>Server Version:</strong> " 436 "<font size=\"+1\"><tt>%s</tt></font></dt>\n", 437 ap_get_server_description()); 438 ap_rprintf(r, 439 "<dt><strong>Server Built:</strong> " 440 "<font size=\"+1\"><tt>%s</tt></font></dt>\n", 441 ap_get_server_built()); 442 ap_rprintf(r, 443 "<dt><strong>Server loaded APR Version:</strong> " 444 "<tt>%s</tt></dt>\n", apr_version_string()); 445 ap_rprintf(r, 446 "<dt><strong>Compiled with APR Version:</strong> " 447 "<tt>%s</tt></dt>\n", APR_VERSION_STRING); 448#if APR_MAJOR_VERSION < 2 449 ap_rprintf(r, 450 "<dt><strong>Server loaded APU Version:</strong> " 451 "<tt>%s</tt></dt>\n", apu_version_string()); 452 ap_rprintf(r, 453 "<dt><strong>Compiled with APU Version:</strong> " 454 "<tt>%s</tt></dt>\n", APU_VERSION_STRING); 455#endif 456 ap_rprintf(r, 457 "<dt><strong>Module Magic Number:</strong> " 458 "<tt>%d:%d</tt></dt>\n", MODULE_MAGIC_NUMBER_MAJOR, 459 MODULE_MAGIC_NUMBER_MINOR); 460 ap_rprintf(r, 461 "<dt><strong>Hostname/port:</strong> " 462 "<tt>%s:%u</tt></dt>\n", 463 ap_escape_html(r->pool, ap_get_server_name(r)), 464 ap_get_server_port(r)); 465 ap_rprintf(r, 466 "<dt><strong>Timeouts:</strong> " 467 "<tt>connection: %d " 468 "keep-alive: %d</tt></dt>", 469 (int) (apr_time_sec(serv->timeout)), 470 (int) (apr_time_sec(serv->keep_alive_timeout))); 471 ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons); 472 ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded); 473 ap_mpm_query(AP_MPMQ_IS_FORKED, &forked); 474 ap_rprintf(r, "<dt><strong>MPM Name:</strong> <tt>%s</tt></dt>\n", 475 ap_show_mpm()); 476 ap_rprintf(r, 477 "<dt><strong>MPM Information:</strong> " 478 "<tt>Max Daemons: %d Threaded: %s Forked: %s</tt></dt>\n", 479 max_daemons, threaded ? "yes" : "no", forked ? "yes" : "no"); 480 ap_rprintf(r, 481 "<dt><strong>Server Architecture:</strong> " 482 "<tt>%ld-bit</tt></dt>\n", 8 * (long) sizeof(void *)); 483 ap_rprintf(r, 484 "<dt><strong>Server Root:</strong> " 485 "<tt>%s</tt></dt>\n", ap_server_root); 486 ap_rprintf(r, 487 "<dt><strong>Config File:</strong> " 488 "<tt>%s</tt></dt>\n", ap_conftree->filename); 489 490 ap_rputs("<dt><strong>Server Built With:</strong>\n" 491 "<tt style=\"white-space: pre;\">\n", r); 492 493 /* TODO: Not all of these defines are getting set like they do in main.c. 494 * Missing some headers? 495 */ 496 497#ifdef BIG_SECURITY_HOLE 498 ap_rputs(" -D BIG_SECURITY_HOLE\n", r); 499#endif 500 501#ifdef SECURITY_HOLE_PASS_AUTHORIZATION 502 ap_rputs(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n", r); 503#endif 504 505#ifdef OS 506 ap_rputs(" -D OS=\"" OS "\"\n", r); 507#endif 508 509#ifdef HAVE_SHMGET 510 ap_rputs(" -D HAVE_SHMGET\n", r); 511#endif 512 513#if APR_FILE_BASED_SHM 514 ap_rputs(" -D APR_FILE_BASED_SHM\n", r); 515#endif 516 517#if APR_HAS_SENDFILE 518 ap_rputs(" -D APR_HAS_SENDFILE\n", r); 519#endif 520 521#if APR_HAS_MMAP 522 ap_rputs(" -D APR_HAS_MMAP\n", r); 523#endif 524 525#ifdef NO_WRITEV 526 ap_rputs(" -D NO_WRITEV\n", r); 527#endif 528 529#ifdef NO_LINGCLOSE 530 ap_rputs(" -D NO_LINGCLOSE\n", r); 531#endif 532 533#if APR_HAVE_IPV6 534 ap_rputs(" -D APR_HAVE_IPV6 (IPv4-mapped addresses ", r); 535#ifdef AP_ENABLE_V4_MAPPED 536 ap_rputs("enabled)\n", r); 537#else 538 ap_rputs("disabled)\n", r); 539#endif 540#endif 541 542#if APR_USE_FLOCK_SERIALIZE 543 ap_rputs(" -D APR_USE_FLOCK_SERIALIZE\n", r); 544#endif 545 546#if APR_USE_SYSVSEM_SERIALIZE 547 ap_rputs(" -D APR_USE_SYSVSEM_SERIALIZE\n", r); 548#endif 549 550#if APR_USE_POSIXSEM_SERIALIZE 551 ap_rputs(" -D APR_USE_POSIXSEM_SERIALIZE\n", r); 552#endif 553 554#if APR_USE_FCNTL_SERIALIZE 555 ap_rputs(" -D APR_USE_FCNTL_SERIALIZE\n", r); 556#endif 557 558#if APR_USE_PROC_PTHREAD_SERIALIZE 559 ap_rputs(" -D APR_USE_PROC_PTHREAD_SERIALIZE\n", r); 560#endif 561#if APR_PROCESS_LOCK_IS_GLOBAL 562 ap_rputs(" -D APR_PROCESS_LOCK_IS_GLOBAL\n", r); 563#endif 564 565#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT 566 ap_rputs(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n", r); 567#endif 568 569#if APR_HAS_OTHER_CHILD 570 ap_rputs(" -D APR_HAS_OTHER_CHILD\n", r); 571#endif 572 573#ifdef AP_HAVE_RELIABLE_PIPED_LOGS 574 ap_rputs(" -D AP_HAVE_RELIABLE_PIPED_LOGS\n", r); 575#endif 576 577#ifdef BUFFERED_LOGS 578 ap_rputs(" -D BUFFERED_LOGS\n", r); 579#ifdef PIPE_BUF 580 ap_rputs(" -D PIPE_BUF=%ld\n", (long) PIPE_BUF, r); 581#endif 582#endif 583 584#if APR_CHARSET_EBCDIC 585 ap_rputs(" -D APR_CHARSET_EBCDIC\n", r); 586#endif 587 588#ifdef NEED_HASHBANG_EMUL 589 ap_rputs(" -D NEED_HASHBANG_EMUL\n", r); 590#endif 591 592/* This list displays the compiled in default paths: */ 593#ifdef HTTPD_ROOT 594 ap_rputs(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n", r); 595#endif 596 597#ifdef SUEXEC_BIN 598 ap_rputs(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n", r); 599#endif 600 601#ifdef DEFAULT_PIDLOG 602 ap_rputs(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n", r); 603#endif 604 605#ifdef DEFAULT_SCOREBOARD 606 ap_rputs(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n", r); 607#endif 608 609#ifdef DEFAULT_ERRORLOG 610 ap_rputs(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n", r); 611#endif 612 613 614#ifdef AP_TYPES_CONFIG_FILE 615 ap_rputs(" -D AP_TYPES_CONFIG_FILE=\"" AP_TYPES_CONFIG_FILE "\"\n", r); 616#endif 617 618#ifdef SERVER_CONFIG_FILE 619 ap_rputs(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n", r); 620#endif 621 ap_rputs("</tt></dt>\n", r); 622 ap_rputs("</dl><hr />", r); 623 return 0; 624} 625 626static int dump_a_hook(request_rec * r, hook_get_t hook_get) 627{ 628 int i; 629 char qs; 630 hook_struct_t *elts; 631 apr_array_header_t *hooks = hook_get(); 632 633 if (!hooks) { 634 return 0; 635 } 636 637 if (r->args && strcasecmp(r->args, "hooks") == 0) { 638 qs = '?'; 639 } 640 else { 641 qs = '#'; 642 } 643 644 elts = (hook_struct_t *) hooks->elts; 645 646 for (i = 0; i < hooks->nelts; i++) { 647 ap_rprintf(r, 648 " %02d <a href=\"%c%s\">%s</a> <br/>", 649 elts[i].nOrder, qs, elts[i].szName, elts[i].szName); 650 } 651 return 0; 652} 653 654static int show_active_hooks(request_rec * r) 655{ 656 int i; 657 ap_rputs("<h2><a name=\"startup_hooks\">Startup Hooks</a></h2>\n<dl>", r); 658 659 for (i = 0; startup_hooks[i].name; i++) { 660 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n", 661 startup_hooks[i].name); 662 dump_a_hook(r, startup_hooks[i].get); 663 ap_rputs("\n </tt>\n</dt>\n", r); 664 } 665 666 ap_rputs 667 ("</dl>\n<hr />\n<h2><a name=\"request_hooks\">Request Hooks</a></h2>\n<dl>", 668 r); 669 670 for (i = 0; request_hooks[i].name; i++) { 671 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n", 672 request_hooks[i].name); 673 dump_a_hook(r, request_hooks[i].get); 674 ap_rputs("\n </tt>\n</dt>\n", r); 675 } 676 677 ap_rputs 678 ("</dl>\n<hr />\n<h2><a name=\"other_hooks\">Other Hooks</a></h2>\n<dl>", 679 r); 680 681 for (i = 0; other_hooks[i].name; i++) { 682 ap_rprintf(r, "<dt><strong>%s:</strong>\n <br /><tt>\n", 683 other_hooks[i].name); 684 dump_a_hook(r, other_hooks[i].get); 685 ap_rputs("\n </tt>\n</dt>\n", r); 686 } 687 688 ap_rputs("</dl>\n<hr />\n", r); 689 690 return 0; 691} 692 693static int cmp_provider_groups(const void *a_, const void *b_) 694{ 695 const ap_list_provider_groups_t *a = a_, *b = b_; 696 int ret = strcmp(a->provider_group, b->provider_group); 697 if (!ret) 698 ret = strcmp(a->provider_version, b->provider_version); 699 return ret; 700} 701 702static int cmp_provider_names(const void *a_, const void *b_) 703{ 704 const ap_list_provider_names_t *a = a_, *b = b_; 705 return strcmp(a->provider_name, b->provider_name); 706} 707 708static void show_providers(request_rec *r) 709{ 710 apr_array_header_t *groups = ap_list_provider_groups(r->pool); 711 ap_list_provider_groups_t *group; 712 apr_array_header_t *names; 713 ap_list_provider_names_t *name; 714 int i,j; 715 const char *cur_group = NULL; 716 717 qsort(groups->elts, groups->nelts, sizeof(ap_list_provider_groups_t), 718 cmp_provider_groups); 719 ap_rputs("<h2><a name=\"providers\">Providers</a></h2>\n<dl>", r); 720 721 for (i = 0; i < groups->nelts; i++) { 722 group = &APR_ARRAY_IDX(groups, i, ap_list_provider_groups_t); 723 if (!cur_group || strcmp(cur_group, group->provider_group) != 0) { 724 if (cur_group) 725 ap_rputs("\n</dt>\n", r); 726 cur_group = group->provider_group; 727 ap_rprintf(r, "<dt><strong>%s</strong> (version <tt>%s</tt>):" 728 "\n <br />\n", cur_group, group->provider_version); 729 } 730 names = ap_list_provider_names(r->pool, group->provider_group, 731 group->provider_version); 732 qsort(names->elts, names->nelts, sizeof(ap_list_provider_names_t), 733 cmp_provider_names); 734 for (j = 0; j < names->nelts; j++) { 735 name = &APR_ARRAY_IDX(names, j, ap_list_provider_names_t); 736 ap_rprintf(r, "<tt> %s</tt><br/>", name->provider_name); 737 } 738 } 739 if (cur_group) 740 ap_rputs("\n</dt>\n", r); 741 ap_rputs("</dl>\n<hr />\n", r); 742} 743 744static int cmp_module_name(const void *a_, const void *b_) 745{ 746 const module * const *a = a_; 747 const module * const *b = b_; 748 return strcmp((*a)->name, (*b)->name); 749} 750 751static apr_array_header_t *get_sorted_modules(apr_pool_t *p) 752{ 753 apr_array_header_t *arr = apr_array_make(p, 64, sizeof(module *)); 754 module *modp, **entry; 755 for (modp = ap_top_module; modp; modp = modp->next) { 756 entry = &APR_ARRAY_PUSH(arr, module *); 757 *entry = modp; 758 } 759 qsort(arr->elts, arr->nelts, sizeof(module *), cmp_module_name); 760 return arr; 761} 762 763static int display_info(request_rec * r) 764{ 765 module *modp = NULL; 766 const char *more_info; 767 const command_rec *cmd; 768 apr_array_header_t *modules = NULL; 769 int i; 770 771 if (strcmp(r->handler, "server-info")) { 772 return DECLINED; 773 } 774 775 r->allowed |= (AP_METHOD_BIT << M_GET); 776 if (r->method_number != M_GET) { 777 return DECLINED; 778 } 779 780 ap_set_content_type(r, "text/html; charset=ISO-8859-1"); 781 782 ap_rputs(DOCTYPE_XHTML_1_0T 783 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" 784 "<head>\n" 785 " <title>Server Information</title>\n" "</head>\n", r); 786 ap_rputs("<body><h1 style=\"text-align: center\">" 787 "Apache Server Information</h1>\n", r); 788 if (!r->args || strcasecmp(r->args, "list")) { 789 if (!r->args) { 790 ap_rputs("<dl><dt><tt>Subpages:<br />", r); 791 ap_rputs("<a href=\"?config\">Configuration Files</a>, " 792 "<a href=\"?server\">Server Settings</a>, " 793 "<a href=\"?list\">Module List</a>, " 794 "<a href=\"?hooks\">Active Hooks</a>, " 795 "<a href=\"?providers\">Available Providers</a>", r); 796 ap_rputs("</tt></dt></dl><hr />", r); 797 798 ap_rputs("<dl><dt><tt>Sections:<br />", r); 799 ap_rputs("<a href=\"#modules\">Loaded Modules</a>, " 800 "<a href=\"#server\">Server Settings</a>, " 801 "<a href=\"#startup_hooks\">Startup Hooks</a>, " 802 "<a href=\"#request_hooks\">Request Hooks</a>, " 803 "<a href=\"#other_hooks\">Other Hooks</a>, " 804 "<a href=\"#providers\">Providers</a>", r); 805 ap_rputs("</tt></dt></dl><hr />", r); 806 807 ap_rputs("<h2><a name=\"modules\">Loaded Modules</a></h2>" 808 "<dl><dt><tt>", r); 809 810 modules = get_sorted_modules(r->pool); 811 for (i = 0; i < modules->nelts; i++) { 812 modp = APR_ARRAY_IDX(modules, i, module *); 813 ap_rprintf(r, "<a href=\"#%s\">%s</a>", modp->name, 814 modp->name); 815 if (i < modules->nelts) { 816 ap_rputs(", ", r); 817 } 818 } 819 ap_rputs("</tt></dt></dl><hr />", r); 820 } 821 822 if (!r->args || !strcasecmp(r->args, "server")) { 823 show_server_settings(r); 824 } 825 826 if (!r->args || !strcasecmp(r->args, "hooks")) { 827 show_active_hooks(r); 828 } 829 830 if (!r->args || !strcasecmp(r->args, "providers")) { 831 show_providers(r); 832 } 833 834 if (r->args && 0 == strcasecmp(r->args, "config")) { 835 ap_rputs("<dl><dt><strong>Configuration:</strong>\n", r); 836 mod_info_module_cmds(r, NULL, ap_conftree, 0, 0); 837 ap_rputs("</dl><hr />", r); 838 } 839 else { 840 int comma = 0; 841 if (!modules) 842 modules = get_sorted_modules(r->pool); 843 for (i = 0; i < modules->nelts; i++) { 844 modp = APR_ARRAY_IDX(modules, i, module *); 845 if (!r->args || !strcasecmp(modp->name, r->args)) { 846 ap_rprintf(r, 847 "<dl><dt><a name=\"%s\"><strong>Module Name:</strong></a> " 848 "<font size=\"+1\"><tt><a href=\"?%s\">%s</a></tt></font></dt>\n", 849 modp->name, modp->name, modp->name); 850 ap_rputs("<dt><strong>Content handlers:</strong> ", r); 851 852 if (module_find_hook(modp, ap_hook_get_handler)) { 853 ap_rputs("<tt> <em>yes</em></tt>", r); 854 } 855 else { 856 ap_rputs("<tt> <em>none</em></tt>", r); 857 } 858 859 ap_rputs("</dt>", r); 860 ap_rputs 861 ("<dt><strong>Configuration Phase Participation:</strong>\n", 862 r); 863 if (modp->create_dir_config) { 864 if (comma) { 865 ap_rputs(", ", r); 866 } 867 ap_rputs("<tt>Create Directory Config</tt>", r); 868 comma = 1; 869 } 870 if (modp->merge_dir_config) { 871 if (comma) { 872 ap_rputs(", ", r); 873 } 874 ap_rputs("<tt>Merge Directory Configs</tt>", r); 875 comma = 1; 876 } 877 if (modp->create_server_config) { 878 if (comma) { 879 ap_rputs(", ", r); 880 } 881 ap_rputs("<tt>Create Server Config</tt>", r); 882 comma = 1; 883 } 884 if (modp->merge_server_config) { 885 if (comma) { 886 ap_rputs(", ", r); 887 } 888 ap_rputs("<tt>Merge Server Configs</tt>", r); 889 comma = 1; 890 } 891 if (!comma) 892 ap_rputs("<tt> <em>none</em></tt>", r); 893 comma = 0; 894 ap_rputs("</dt>", r); 895 896 module_request_hook_participate(r, modp); 897 898 cmd = modp->cmds; 899 if (cmd) { 900 ap_rputs 901 ("<dt><strong>Module Directives:</strong></dt>", 902 r); 903 while (cmd) { 904 if (cmd->name) { 905 ap_rprintf(r, "<dd><tt>%s%s - <i>", 906 ap_escape_html(r->pool, cmd->name), 907 cmd->name[0] == '<' ? ">" : ""); 908 if (cmd->errmsg) { 909 ap_rputs(ap_escape_html(r->pool, cmd->errmsg), r); 910 } 911 ap_rputs("</i></tt></dd>\n", r); 912 } 913 else { 914 break; 915 } 916 cmd++; 917 } 918 ap_rputs 919 ("<dt><strong>Current Configuration:</strong></dt>\n", 920 r); 921 mod_info_module_cmds(r, modp->cmds, ap_conftree, 0, 922 0); 923 } 924 else { 925 ap_rputs 926 ("<dt><strong>Module Directives:</strong> <tt>none</tt></dt>", 927 r); 928 } 929 more_info = find_more_info(r->server, modp->name); 930 if (more_info) { 931 ap_rputs 932 ("<dt><strong>Additional Information:</strong>\n</dt><dd>", 933 r); 934 ap_rputs(more_info, r); 935 ap_rputs("</dd>", r); 936 } 937 ap_rputs("</dl><hr />\n", r); 938 if (r->args) { 939 break; 940 } 941 } 942 } 943 if (!modp && r->args && strcasecmp(r->args, "server")) { 944 ap_rputs("<p><b>No such module</b></p>\n", r); 945 } 946 } 947 } 948 else { 949 ap_rputs("<dl><dt>Server Module List</dt>", r); 950 modules = get_sorted_modules(r->pool); 951 for (i = 0; i < modules->nelts; i++) { 952 modp = APR_ARRAY_IDX(modules, i, module *); 953 ap_rputs("<dd>", r); 954 ap_rputs(modp->name, r); 955 ap_rputs("</dd>", r); 956 } 957 ap_rputs("</dl><hr />", r); 958 } 959 ap_rputs(ap_psignature("", r), r); 960 ap_rputs("</body></html>\n", r); 961 /* Done, turn off timeout, close file and return */ 962 return 0; 963} 964 965static const char *add_module_info(cmd_parms * cmd, void *dummy, 966 const char *name, const char *info) 967{ 968 server_rec *s = cmd->server; 969 info_svr_conf *conf = 970 (info_svr_conf *) ap_get_module_config(s->module_config, 971 &info_module); 972 info_entry *new = apr_array_push(conf->more_info); 973 974 new->name = name; 975 new->info = info; 976 return NULL; 977} 978 979static const command_rec info_cmds[] = { 980 AP_INIT_TAKE2("AddModuleInfo", add_module_info, NULL, RSRC_CONF, 981 "a module name and additional information on that module"), 982 {NULL} 983}; 984 985static int check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, 986 server_rec *s) 987{ 988 if (ap_exists_config_define("DUMP_CONFIG")) { 989 apr_file_open_stdout(&out, ptemp); 990 mod_info_module_cmds(NULL, NULL, ap_conftree, 0, 0); 991 } 992 993 return DECLINED; 994} 995 996 997static void register_hooks(apr_pool_t * p) 998{ 999 ap_hook_handler(display_info, NULL, NULL, APR_HOOK_MIDDLE); 1000 ap_hook_check_config(check_config, NULL, NULL, APR_HOOK_FIRST); 1001} 1002 1003AP_DECLARE_MODULE(info) = { 1004 STANDARD20_MODULE_STUFF, 1005 NULL, /* dir config creater */ 1006 NULL, /* dir merger --- default is to override */ 1007 create_info_config, /* server config */ 1008 merge_info_config, /* merge server config */ 1009 info_cmds, /* command apr_table_t */ 1010 register_hooks 1011}; 1012