1 /* ====================================================================
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 *
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
57 */
58
59 /*
60 * Info Module. Display configuration information for the server and
61 * all included modules.
62 *
63 * <Location /server-info>
64 * SetHandler server-info
65 * </Location>
66 *
67 * GET /server-info - Returns full configuration page for server and all modules
68 * GET /server-info?server - Returns server configuration only
69 * GET /server-info?module_name - Returns configuration for a single module
70 * GET /server-info?list - Returns quick list of included modules
71 *
72 * Rasmus Lerdorf <rasmus@php.net>, May 1996
73 *
74 * 05.01.96 Initial Version
75 *
76 * Lou Langholtz <ldl@usi.utah.edu>, July 1997
77 *
78 * 07.11.97 Addition of the AddModuleInfo directive
79 *
80 */
81
82 #include "httpd.h"
83 #include "http_config.h"
84 #include "http_core.h"
85 #include "http_log.h"
86 #include "http_main.h"
87 #include "http_protocol.h"
88 #include "util_script.h"
89 #include "http_conf_globals.h"
90
91 __RCSID("$MirOS: src/usr.sbin/httpd/src/modules/standard/mod_info.c,v 1.2 2008/12/03 11:23:01 tg Exp $");
92
93 typedef struct {
94 char *name; /* matching module name */
95 char *info; /* additional info */
96 } info_entry;
97
98 typedef struct {
99 array_header *more_info;
100 } info_svr_conf;
101
102 typedef struct info_cfg_lines {
103 char *cmd;
104 char *line;
105 struct info_cfg_lines *next;
106 } info_cfg_lines;
107
108 typedef struct { /* shamelessly lifted from http_config.c */
109 char *fname;
110 } info_fnames;
111
112 typedef struct {
113 info_cfg_lines *clines;
114 char *fname;
115 } info_clines;
116
117 module MODULE_VAR_EXPORT info_module;
118 extern module API_VAR_EXPORT *top_module;
119
120 /* shamelessly lifted from http_config.c */
fname_alphasort(const void * fn1,const void * fn2)121 static int fname_alphasort(const void *fn1, const void *fn2)
122 {
123 const info_fnames *f1 = fn1;
124 const info_fnames *f2 = fn2;
125
126 return strcmp(f1->fname,f2->fname);
127 }
128
create_info_config(pool * p,server_rec * s)129 static void *create_info_config(pool *p, server_rec *s)
130 {
131 info_svr_conf *conf = (info_svr_conf *) ap_pcalloc(p, sizeof(info_svr_conf));
132
133 conf->more_info = ap_make_array(p, 20, sizeof(info_entry));
134 return conf;
135 }
136
merge_info_config(pool * p,void * basev,void * overridesv)137 static void *merge_info_config(pool *p, void *basev, void *overridesv)
138 {
139 info_svr_conf *new = (info_svr_conf *) ap_pcalloc(p, sizeof(info_svr_conf));
140 info_svr_conf *base = (info_svr_conf *) basev;
141 info_svr_conf *overrides = (info_svr_conf *) overridesv;
142
143 new->more_info = ap_append_arrays(p, overrides->more_info, base->more_info);
144 return new;
145 }
146
mod_info_html_cmd_string(const char * string,char * buf,size_t buf_len)147 static char *mod_info_html_cmd_string(const char *string, char *buf, size_t buf_len)
148 {
149 const char *s;
150 char *t;
151 char *end_buf;
152
153 s = string;
154 t = buf;
155 /* keep space for \0 byte */
156 end_buf = buf + buf_len - 1;
157 while ((*s) && (t < end_buf)) {
158 if (*s == '<') {
159 strncpy(t, "<", end_buf - t);
160 t += 4;
161 }
162 else if (*s == '>') {
163 strncpy(t, ">", end_buf - t);
164 t += 4;
165 }
166 else if (*s == '&') {
167 strncpy(t, "&", end_buf - t);
168 t += 5;
169 }
170 else {
171 *t++ = *s;
172 }
173 s++;
174 }
175 /* oops, overflowed... don't overwrite */
176 if (t > end_buf) {
177 *end_buf = '\0';
178 }
179 else {
180 *t = '\0';
181 }
182 return (buf);
183 }
184
mod_info_load_config(pool * p,const char * filename,request_rec * r)185 static info_cfg_lines *mod_info_load_config(pool *p, const char *filename,
186 request_rec *r)
187 {
188 char s[MAX_STRING_LEN];
189 configfile_t *fp;
190 info_cfg_lines *new, *ret, *prev;
191 const char *t;
192
193 fp = ap_pcfg_openfile(p, filename);
194 if (!fp) {
195 ap_log_rerror(APLOG_MARK, APLOG_WARNING, r,
196 "mod_info: couldn't open config file %s",
197 filename);
198 return NULL;
199 }
200 ret = NULL;
201 prev = NULL;
202 while (!ap_cfg_getline(s, MAX_STRING_LEN, fp)) {
203 if (*s == '#') {
204 continue; /* skip comments */
205 }
206 new = ap_palloc(p, sizeof(struct info_cfg_lines));
207 new->next = NULL;
208 if (!ret) {
209 ret = new;
210 }
211 if (prev) {
212 prev->next = new;
213 }
214 t = s;
215 new->cmd = ap_getword_conf(p, &t);
216 if (*t) {
217 new->line = ap_pstrdup(p, t);
218 }
219 else {
220 new->line = NULL;
221 }
222 prev = new;
223 }
224 ap_cfg_closefile(fp);
225 return (ret);
226 }
227
mod_info_module_cmds(request_rec * r,info_cfg_lines * cfg,const command_rec * cmds,char * label)228 static void mod_info_module_cmds(request_rec *r, info_cfg_lines *cfg,
229 const command_rec *cmds, char *label)
230 {
231 const command_rec *cmd = cmds;
232 info_cfg_lines *li = cfg, *li_st = NULL, *li_se = NULL;
233 info_cfg_lines *block_start = NULL;
234 int lab = 0, nest = 0;
235 char buf[MAX_STRING_LEN];
236
237 while (li) {
238 if (!strncasecmp(li->cmd, "<directory", 10) ||
239 !strncasecmp(li->cmd, "<location", 9) ||
240 !strncasecmp(li->cmd, "<limit", 6) ||
241 !strncasecmp(li->cmd, "<files", 6)) {
242 if (nest) {
243 li_se = li;
244 }
245 else {
246 li_st = li;
247 }
248 li = li->next;
249 nest++;
250 continue;
251 }
252 else if (nest && (!strncasecmp(li->cmd, "</limit", 7) ||
253 !strncasecmp(li->cmd, "</location", 10) ||
254 !strncasecmp(li->cmd, "</directory", 11) ||
255 !strncasecmp(li->cmd, "</files", 7))) {
256 if (block_start) {
257 if ((nest == 1 && block_start == li_st) ||
258 (nest == 2 && block_start == li_se)) {
259 ap_rputs("<dd><tt>", r);
260 if (nest == 2) {
261 ap_rputs(" ", r);
262 }
263 ap_rputs(mod_info_html_cmd_string(li->cmd, buf, sizeof(buf)), r);
264 ap_rputs(" ", r);
265 if (li->line) {
266 ap_rputs(mod_info_html_cmd_string(li->line, buf, sizeof(buf)), r);
267 }
268 ap_rputs("</tt>\n", r);
269 nest--;
270 if (!nest) {
271 block_start = NULL;
272 li_st = NULL;
273 }
274 else {
275 block_start = li_st;
276 }
277 li_se = NULL;
278 }
279 else {
280 nest--;
281 if (!nest) {
282 li_st = NULL;
283 }
284 li_se = NULL;
285 }
286 }
287 else {
288 nest--;
289 if (!nest) {
290 li_st = NULL;
291 }
292 li_se = NULL;
293 }
294 li = li->next;
295 continue;
296 }
297 cmd = cmds;
298 while (cmd) {
299 if (cmd->name) {
300 if (!strcasecmp(cmd->name, li->cmd)) {
301 if (!lab) {
302 ap_rputs("<dt><strong>", r);
303 ap_rputs(label, r);
304 ap_rputs("</strong>\n", r);
305 lab = 1;
306 }
307 if (((nest && block_start == NULL) ||
308 (nest == 2 && block_start == li_st)) &&
309 (strncasecmp(li->cmd, "<directory", 10) &&
310 strncasecmp(li->cmd, "<location", 9) &&
311 strncasecmp(li->cmd, "<limit", 6) &&
312 strncasecmp(li->cmd, "</limit", 7) &&
313 strncasecmp(li->cmd, "</location", 10) &&
314 strncasecmp(li->cmd, "</directory", 11) &&
315 strncasecmp(li->cmd, "</files", 7))) {
316 ap_rputs("<dd><tt>", r);
317 ap_rputs(mod_info_html_cmd_string(li_st->cmd, buf, sizeof(buf)), r);
318 ap_rputs(" ", r);
319 if (li_st->line) {
320 ap_rputs(mod_info_html_cmd_string(li_st->line, buf, sizeof(buf)), r);
321 }
322 ap_rputs("</tt>\n", r);
323 block_start = li_st;
324 if (li_se) {
325 ap_rputs("<dd><tt> ", r);
326 ap_rputs(mod_info_html_cmd_string(li_se->cmd, buf, sizeof(buf)), r);
327 ap_rputs(" ", r);
328 if (li_se->line) {
329 ap_rputs(mod_info_html_cmd_string(li_se->line, buf, sizeof(buf)), r);
330 }
331 ap_rputs("</tt>\n", r);
332 block_start = li_se;
333 }
334 }
335 ap_rputs("<dd><tt>", r);
336 if (nest) {
337 ap_rputs(" ", r);
338 }
339 if (nest == 2) {
340 ap_rputs(" ", r);
341 }
342 ap_rputs(mod_info_html_cmd_string(li->cmd, buf, sizeof(buf)), r);
343 if (li->line) {
344 ap_rputs(" <i>", r);
345 ap_rputs(mod_info_html_cmd_string(li->line, buf, sizeof(buf)), r);
346 ap_rputs("</i>", r);
347 }
348 ap_rputs("</tt>", r);
349 }
350 }
351 else
352 break;
353 cmd++;
354 }
355 li = li->next;
356 }
357 }
358
find_more_info(server_rec * s,const char * module_name)359 static char *find_more_info(server_rec *s, const char *module_name)
360 {
361 int i;
362 info_svr_conf *conf = (info_svr_conf *) ap_get_module_config(s->module_config,
363 &info_module);
364 info_entry *entry = (info_entry *) conf->more_info->elts;
365
366 if (!module_name) {
367 return 0;
368 }
369 for (i = 0; i < conf->more_info->nelts; i++) {
370 if (!strcmp(module_name, entry->name)) {
371 return entry->info;
372 }
373 entry++;
374 }
375 return 0;
376 }
377
mod_info_dirwalk(pool * p,const char * fname,request_rec * r,array_header * carray)378 static void mod_info_dirwalk(pool *p, const char *fname,
379 request_rec *r, array_header *carray)
380 {
381 info_clines *cnew = NULL;
382 info_cfg_lines *mod_info_cfg_tmp = NULL;
383
384 if (!ap_is_rdirectory(fname)) {
385 mod_info_cfg_tmp = mod_info_load_config(p, fname, r);
386 cnew = (info_clines *) ap_push_array(carray);
387 cnew->fname = ap_pstrdup(p, fname);
388 cnew->clines = mod_info_cfg_tmp;
389 } else {
390 DIR *dirp;
391 struct DIR_TYPE *dir_entry;
392 int current;
393 array_header *candidates = NULL;
394 info_fnames *fnew;
395
396 dirp = ap_popendir(p, fname);
397 if (dirp == NULL) {
398 ap_log_rerror(APLOG_MARK, APLOG_WARNING, r,
399 "mod_info: couldn't open config directory %s",
400 fname);
401 return;
402 }
403 candidates = ap_make_array(p, 1, sizeof(info_fnames));
404 while ((dir_entry = readdir(dirp)) != NULL) {
405 /* strip out '.' and '..' */
406 if (strcmp(dir_entry->d_name, ".") &&
407 strcmp(dir_entry->d_name, "..")) {
408 fnew = (info_fnames *) ap_push_array(candidates);
409 fnew->fname = ap_make_full_path(p, fname, dir_entry->d_name);
410 }
411 }
412 ap_pclosedir(p, dirp);
413 if (candidates->nelts != 0) {
414 qsort((void *) candidates->elts, candidates->nelts,
415 sizeof(info_fnames), fname_alphasort);
416 for (current = 0; current < candidates->nelts; ++current) {
417 fnew = &((info_fnames *) candidates->elts)[current];
418 mod_info_dirwalk(p, fnew->fname, r, carray);
419 }
420 }
421 }
422 return;
423 }
424
display_info(request_rec * r)425 static int display_info(request_rec *r)
426 {
427 module *modp = NULL;
428 char buf[MAX_STRING_LEN], *cfname;
429 char *more_info;
430 const command_rec *cmd = NULL;
431 const handler_rec *hand = NULL;
432 server_rec *serv = r->server;
433 int comma = 0;
434 array_header *allconfigs = NULL;
435 info_clines *cnew = NULL;
436 int current;
437 char *relpath;
438
439 r->allowed |= (1 << M_GET);
440 if (r->method_number != M_GET)
441 return DECLINED;
442
443 r->content_type = "text/html";
444 ap_send_http_header(r);
445 if (r->header_only) {
446 return 0;
447 }
448 ap_hard_timeout("send server info", r);
449
450 ap_rputs(DOCTYPE_HTML_3_2
451 "<html><head><title>Server Information</title></head>\n", r);
452 ap_rputs("<body><h1 align=center>Apache Server Information</h1>\n", r);
453 if (!r->args || strcasecmp(r->args, "list")) {
454 allconfigs = ap_make_array(r->pool, 1, sizeof(info_clines));
455 cfname = ap_server_root_relative(r->pool, ap_server_confname);
456 mod_info_dirwalk(r->pool, cfname, r, allconfigs);
457 cfname = ap_server_root_relative(r->pool, serv->srm_confname);
458 mod_info_dirwalk(r->pool, cfname, r, allconfigs);
459 cfname = ap_server_root_relative(r->pool, serv->access_confname);
460 mod_info_dirwalk(r->pool, cfname, r, allconfigs);
461 if (!r->args) {
462 ap_rputs("<tt><a href=\"#server\">Server Settings</a>, ", r);
463 for (modp = top_module; modp; modp = modp->next) {
464 ap_rprintf(r, "<a href=\"#%s\">%s</a>", modp->name, modp->name);
465 if (modp->next) {
466 ap_rputs(", ", r);
467 }
468 }
469 ap_rputs("</tt><hr>", r);
470
471 }
472 if (!r->args || !strcasecmp(r->args, "server")) {
473 ap_rprintf(r, "<a name=\"server\"><strong>Server Version:</strong> "
474 "<font size=+1><tt>%s</tt></a></font><br>\n",
475 ap_get_server_version());
476 ap_rprintf(r, "<strong>API Version:</strong> "
477 "<tt>%d:%d</tt><br>\n",
478 MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR);
479 ap_rprintf(r, "<strong>Run Mode:</strong> <tt>%s</tt><br>\n",
480 (ap_standalone ? "standalone" : "inetd"));
481 ap_rprintf(r, "<strong>User/Group:</strong> "
482 "<tt>%s(%d)/%d</tt><br>\n",
483 ap_user_name, (int) ap_user_id, (int) ap_group_id);
484 ap_rprintf(r, "<strong>Hostname/port:</strong> "
485 "<tt>%s:%u</tt><br>\n",
486 serv->server_hostname, serv->port);
487 ap_rprintf(r, "<strong>Daemons:</strong> "
488 "<tt>start: %d "
489 "min idle: %d "
490 "max idle: %d "
491 "max: %d</tt><br>\n",
492 ap_daemons_to_start, ap_daemons_min_free,
493 ap_daemons_max_free, ap_daemons_limit);
494 ap_rprintf(r, "<strong>Per-child rlimits:</strong><br>\n"
495 "<tt>RLIMIT_CPU: %d </tt><br>\n"
496 "<tt>RLIMIT_DATA: %d </tt><br>\n"
497 "<tt>RLIMIT_NOFILE: %d </tt><br>\n"
498 "<tt>RLIMIT_RSS: %d </tt><br>\n"
499 "<tt>RLIMIT_STACK: %d </tt><br>\n"
500 #ifdef RLIMIT_TIME
501 "<tt>RLIMIT_TIME: %d </tt><br>\n"
502 #endif
503 ,
504 ap_max_cpu_per_child, ap_max_data_per_child,
505 ap_max_nofile_per_child, ap_max_rss_per_child,
506 ap_max_stack_per_child
507 #ifdef RLIMIT_TIME
508 , ap_max_time_per_child
509 #endif
510 );
511 ap_rprintf(r, "<strong>Max Requests:</strong> "
512 "<tt>per child: %d "
513 "keep alive: %s "
514 "max per connection: %d</tt><br>\n",
515 ap_max_requests_per_child,
516 (serv->keep_alive ? "on" : "off"),
517 serv->keep_alive_max);
518 ap_rprintf(r, "<strong>Threads:</strong> "
519 "<tt>per child: %d </tt><br>\n",
520 ap_threads_per_child);
521 ap_rprintf(r, "<strong>Excess requests:</strong> "
522 "<tt>per child: %d </tt><br>\n",
523 ap_excess_requests_per_child);
524 ap_rprintf(r, "<strong>Timeouts:</strong> "
525 "<tt>connection: %d "
526 "keep-alive: %d</tt><br>",
527 serv->timeout, serv->keep_alive_timeout);
528 ap_rprintf(r, "<strong>Server Root:</strong> "
529 "<tt>%s</tt><br>\n", ap_server_root);
530 ap_rprintf(r, "<strong>Config File:</strong> "
531 "<tt>%s</tt><br>\n", ap_server_confname);
532 ap_rprintf(r, "<strong>PID File:</strong> "
533 "<tt>%s</tt><br>\n", ap_pid_fname);
534 ap_rprintf(r, "<strong>Scoreboard File:</strong> "
535 "<tt>%s</tt><br>\n", ap_scoreboard_fname);
536 }
537 ap_rputs("<hr><dl>", r);
538 for (modp = top_module; modp; modp = modp->next) {
539 if (!r->args || !strcasecmp(modp->name, r->args)) {
540 ap_rprintf(r, "<dt><a name=\"%s\"><strong>Module Name:</strong> "
541 "<font size=+1><tt>%s</tt></a></font>\n",
542 modp->name, modp->name);
543 ap_rputs("<dt><strong>Content handlers:</strong>", r);
544 hand = modp->handlers;
545 if (hand) {
546 while (hand) {
547 if (hand->content_type) {
548 ap_rprintf(r, " <tt>%s</tt>\n", hand->content_type);
549 }
550 else {
551 break;
552 }
553 hand++;
554 if (hand && hand->content_type) {
555 ap_rputs(",", r);
556 }
557 }
558 }
559 else {
560 ap_rputs("<tt> <EM>none</EM></tt>", r);
561 }
562 ap_rputs("<dt><strong>Configuration Phase Participation:</strong> \n",
563 r);
564 if (modp->child_init) {
565 ap_rputs("<tt>Child Init</tt>", r);
566 comma = 1;
567 }
568 if (modp->create_dir_config) {
569 if (comma) {
570 ap_rputs(", ", r);
571 }
572 ap_rputs("<tt>Create Directory Config</tt>", r);
573 comma = 1;
574 }
575 if (modp->merge_dir_config) {
576 if (comma) {
577 ap_rputs(", ", r);
578 }
579 ap_rputs("<tt>Merge Directory Configs</tt>", r);
580 comma = 1;
581 }
582 if (modp->create_server_config) {
583 if (comma) {
584 ap_rputs(", ", r);
585 }
586 ap_rputs("<tt>Create Server Config</tt>", r);
587 comma = 1;
588 }
589 if (modp->merge_server_config) {
590 if (comma) {
591 ap_rputs(", ", r);
592 }
593 ap_rputs("<tt>Merge Server Configs</tt>", r);
594 comma = 1;
595 }
596 if (modp->child_exit) {
597 if (comma) {
598 ap_rputs(", ", r);
599 }
600 ap_rputs("<tt>Child Exit</tt>", r);
601 comma = 1;
602 }
603 if (!comma)
604 ap_rputs("<tt> <EM>none</EM></tt>", r);
605 comma = 0;
606 ap_rputs("<dt><strong>Request Phase Participation:</strong> \n",
607 r);
608 if (modp->post_read_request) {
609 ap_rputs("<tt>Post-Read Request</tt>", r);
610 comma = 1;
611 }
612 if (modp->header_parser) {
613 if (comma) {
614 ap_rputs(", ", r);
615 }
616 ap_rputs("<tt>Header Parse</tt>", r);
617 comma = 1;
618 }
619 if (modp->translate_handler) {
620 if (comma) {
621 ap_rputs(", ", r);
622 }
623 ap_rputs("<tt>Translate Path</tt>", r);
624 comma = 1;
625 }
626 if (modp->access_checker) {
627 if (comma) {
628 ap_rputs(", ", r);
629 }
630 ap_rputs("<tt>Check Access</tt>", r);
631 comma = 1;
632 }
633 if (modp->ap_check_user_id) {
634 if (comma) {
635 ap_rputs(", ", r);
636 }
637 ap_rputs("<tt>Verify User ID</tt>", r);
638 comma = 1;
639 }
640 if (modp->auth_checker) {
641 if (comma) {
642 ap_rputs(", ", r);
643 }
644 ap_rputs("<tt>Verify User Access</tt>", r);
645 comma = 1;
646 }
647 if (modp->type_checker) {
648 if (comma) {
649 ap_rputs(", ", r);
650 }
651 ap_rputs("<tt>Check Type</tt>", r);
652 comma = 1;
653 }
654 if (modp->fixer_upper) {
655 if (comma) {
656 ap_rputs(", ", r);
657 }
658 ap_rputs("<tt>Fixups</tt>", r);
659 comma = 1;
660 }
661 if (modp->logger) {
662 if (comma) {
663 ap_rputs(", ", r);
664 }
665 ap_rputs("<tt>Logging</tt>", r);
666 comma = 1;
667 }
668 if (!comma)
669 ap_rputs("<tt> <EM>none</EM></tt>", r);
670 comma = 0;
671 ap_rputs("<dt><strong>Module Directives:</strong> ", r);
672 cmd = modp->cmds;
673 if (cmd) {
674 while (cmd) {
675 if (cmd->name) {
676 ap_rprintf(r, "<dd><tt>%s - <i>",
677 mod_info_html_cmd_string(cmd->name,
678 buf, sizeof(buf)));
679 if (cmd->errmsg) {
680 ap_rputs(cmd->errmsg, r);
681 }
682 ap_rputs("</i></tt>\n", r);
683 }
684 else {
685 break;
686 }
687 cmd++;
688 }
689 ap_rputs("<dt><strong>Current Configuration:</strong>\n", r);
690 for (current = 0; current < allconfigs->nelts; ++current) {
691 cnew = &((info_clines *) allconfigs->elts)[current];
692 /* get relative pathname with some safeguards */
693 relpath = ap_stripprefix(cnew->fname,ap_server_root);
694 if (*relpath != '\0' && relpath != cnew->fname &&
695 *relpath == '/')
696 relpath++;
697 mod_info_module_cmds(r, cnew->clines, modp->cmds,
698 relpath);
699 }
700 }
701 else {
702 ap_rputs("<tt> none</tt>\n", r);
703 }
704 more_info = find_more_info(serv, modp->name);
705 if (more_info) {
706 ap_rputs("<dt><strong>Additional Information:</strong>\n<dd>",
707 r);
708 ap_rputs(more_info, r);
709 }
710 ap_rputs("<dt><hr>\n", r);
711 if (r->args) {
712 break;
713 }
714 }
715 }
716 if (!modp && r->args && strcasecmp(r->args, "server")) {
717 ap_rputs("<b>No such module</b>\n", r);
718 }
719 }
720 else {
721 for (modp = top_module; modp; modp = modp->next) {
722 ap_rputs(modp->name, r);
723 if (modp->next) {
724 ap_rputs("<br>", r);
725 }
726 }
727 }
728 ap_rputs("</dl>\n", r);
729 ap_rputs(ap_psignature("",r), r);
730 ap_rputs("</body></html>\n", r);
731 /* Done, turn off timeout, close file and return */
732 ap_kill_timeout(r);
733 return 0;
734 }
735
add_module_info(cmd_parms * cmd,void * dummy,char * name,char * info)736 static const char *add_module_info(cmd_parms *cmd, void *dummy, char *name,
737 char *info)
738 {
739 server_rec *s = cmd->server;
740 info_svr_conf *conf = (info_svr_conf *) ap_get_module_config(s->module_config,
741 &info_module);
742 info_entry *new = ap_push_array(conf->more_info);
743
744 new->name = name;
745 new->info = info;
746 return NULL;
747 }
748
749 static const command_rec info_cmds[] =
750 {
751 {"AddModuleInfo", add_module_info, NULL, RSRC_CONF, TAKE2,
752 "a module name and additional information on that module"},
753 {NULL}
754 };
755
756 static const handler_rec info_handlers[] =
757 {
758 {"server-info", display_info},
759 {NULL}
760 };
761
762 module MODULE_VAR_EXPORT info_module =
763 {
764 STANDARD_MODULE_STUFF,
765 NULL, /* initializer */
766 NULL, /* dir config creater */
767 NULL, /* dir merger --- default is to override */
768 create_info_config, /* server config */
769 merge_info_config, /* merge server config */
770 info_cmds, /* command table */
771 info_handlers, /* handlers */
772 NULL, /* filename translation */
773 NULL, /* check_user_id */
774 NULL, /* check auth */
775 NULL, /* check access */
776 NULL, /* type_checker */
777 NULL, /* fixups */
778 NULL, /* logger */
779 NULL, /* header parser */
780 NULL, /* child_init */
781 NULL, /* child_exit */
782 NULL /* post read-request */
783 };
784
785