d83e5359a3706e04ffe843a311e0f0e685cb447b
[m6w6/mod-domaintree] / mod_domaintree.c
1 /*
2 * mod_domaintree.c - Apache2
3 *
4 * $Id$
5 *
6 * Copyright 2005 Michael Wallner <mike@iworks.at>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *
21 * <pre>
22 * DomainTreeEnabled On
23 * DomainTreeMaxdepth 25
24 * DomainTreeStripWWW On
25 * DomainTreePrefix /sites
26 * DomainTreeSuffix /html
27 * DomainTreeCache 5
28 * DomainTreeAliasRecursion Off
29 * DomainTreeAlias /??/exmaple /com/exmaple
30 * DomainTreeAlias /???/example /com/example
31 * DomainTreeAlias /*one/ /anyone/
32 * DomainTreeIgnore *.foo.com *.foo.co.uk
33 * DomainTreeForbid html.*
34 *
35 * /sites
36 * +- /at
37 * | +- /co
38 * | | +- /company
39 * | | +- /html
40 * | | +- /sub1
41 * | | | +- /html
42 * | | +- /sub2
43 * | | +- /html
44 * | +- /or
45 * | +- /organisation
46 * | +- /html
47 * +- /com
48 * +- /example
49 * +- /html
50 * </pre>
51 */
52
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56
57 #define MODULE "mod_domaintree"
58 #define AUTHOR "<mike@iworks.at>"
59 #define VERSION "1.5"
60
61 /* {{{ Includes */
62
63 #include "apr.h"
64 #include "apr_lib.h"
65 #include "apr_hash.h"
66 #include "apr_tables.h"
67 #include "apr_strings.h"
68
69 #if APR_HAVE_UNISTD_H
70 #include <unistd.h>
71 #endif
72
73 #define APR_WANT_MEMFUNC
74 #define APR_WANT_STRFUNC
75 #include "apr_want.h"
76
77 #include "httpd.h"
78 #include "http_config.h"
79 #include "http_core.h"
80 #include "http_log.h"
81 #include "http_protocol.h"
82 #include "http_request.h"
83
84 /* }}} */
85 /* {{{ domaintree_module */
86
87 module AP_MODULE_DECLARE_DATA domaintree_module;
88
89 /* }}} */
90 /* {{{ Macros & Types */
91
92 #define DBG 0
93
94 #define MDT_CNF domaintree_conf
95 #define MDT_PTR (&domaintree_module)
96
97 #define GET_MDT_CNF(srv) ((MDT_CNF *) ap_get_module_config((srv)->module_config, MDT_PTR))
98
99 #define IF_SET_ELSE(a, b) (a != -1) ? (a) : (b)
100
101 #define NUL '\0'
102 #define EMPTY(str) ((str == NULL) || (*(str) == NUL))
103 #if DBG
104 # define local static
105 #else
106 # define local static APR_INLINE
107 #endif
108
109 #define DT_LOG_ERR APLOG_MARK, APLOG_ERR, APR_SUCCESS, DT->server, "DomainTree: "
110 #define DT_LOG_WRN APLOG_MARK, APLOG_WARNING, APR_SUCCESS, DT->server, "DomainTree: "
111 #define DT_LOG_DBG APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, DT->server, "DomainTree: "
112
113 typedef int STATUS;
114
115 typedef struct {
116 long recursion;
117 apr_table_t *faketable;
118 } aliases_t;
119
120 typedef struct {
121 char *host;
122 char *path;
123 apr_time_t lacc;
124 apr_pool_t *pool;
125 } dircache_entry_t;
126
127 typedef struct {
128 long clim;
129 apr_hash_t *hmap;
130 apr_pool_t *pool;
131 apr_global_mutex_t *lock;
132 } dircache_t;
133
134 typedef apr_array_header_t *hostlist_t;
135
136 typedef struct {
137 server_rec *server;
138 int enabled;
139 int stripwww;
140 int statroot;
141 long maxdepth;
142 char *prefix;
143 char *suffix;
144 aliases_t aliases;
145 dircache_t dircache;
146 hostlist_t ignore;
147 hostlist_t forbid;
148 } domaintree_conf;
149
150 /* }}} */
151 /* {{{ dircache */
152
153 local char *domaintree_cache_get(MDT_CNF *DT, apr_time_t atime, const char *host)
154 {
155 char *path = NULL;
156 dircache_entry_t *cache_entry;
157
158 apr_global_mutex_lock(DT->dircache.lock);
159
160 if ((cache_entry = apr_hash_get(DT->dircache.hmap, host, APR_HASH_KEY_STRING))) {
161 cache_entry->lacc = atime;
162 path = cache_entry->path;
163 }
164
165 apr_global_mutex_unlock(DT->dircache.lock);
166
167 if (path) {
168 ap_log_error(DT_LOG_DBG "cache hit = %s for %s", path, host);
169 }
170
171 return path;
172 }
173
174 local void domaintree_cache_set(MDT_CNF *DT, apr_time_t atime, const char *host, const char *path)
175 {
176 apr_pool_t *pool;
177 dircache_entry_t *cache_entry;
178
179 apr_pool_create(&pool, DT->dircache.pool);
180 cache_entry = apr_palloc(pool, sizeof(dircache_entry_t));
181
182 cache_entry->pool = pool;
183 cache_entry->lacc = atime;
184 cache_entry->host = apr_pstrdup(pool, host);
185 cache_entry->path = apr_pstrdup(pool, path);
186
187 apr_global_mutex_lock(DT->dircache.lock);
188
189 if (apr_hash_count(DT->dircache.hmap) >= DT->dircache.clim) {
190 apr_hash_index_t *idx;
191 dircache_entry_t *purge_this = NULL;
192
193 ap_log_error(DT_LOG_WRN "reached cache limit (%ld)", DT->dircache.clim);
194
195 for (idx = apr_hash_first(DT->dircache.pool, DT->dircache.hmap); idx; idx = apr_hash_next(idx)) {
196 dircache_entry_t *current;
197
198 apr_hash_this(idx, NULL, NULL, (void *) &current);
199 if ((!purge_this) || (purge_this->lacc > current->lacc)) {
200 purge_this = current;
201 }
202 }
203
204 if (purge_this) {
205 ap_log_error(DT_LOG_DBG "cache del = %s", purge_this->host);
206 apr_hash_set(DT->dircache.hmap, purge_this->host, APR_HASH_KEY_STRING, NULL);
207 apr_pool_destroy(purge_this->pool);
208 }
209 }
210 apr_hash_set(DT->dircache.hmap, cache_entry->host, APR_HASH_KEY_STRING, cache_entry);
211
212 apr_global_mutex_unlock(DT->dircache.lock);
213
214 ap_log_error(DT_LOG_DBG "cache set = %s for %s", path, host);
215 }
216
217 /* }}} */
218 /* {{{ Helpers */
219
220 local char *strtr(char *string, char from, char to)
221 {
222 char *ptr = string;
223
224 if (from != to) {
225 while ((ptr = strchr(ptr, from))) {
226 *ptr = to;
227 }
228 }
229 return string;
230 }
231
232 #define TRIM_LEFT 1
233 #define TRIM_RIGHT 2
234 #define TRIM_BOTH (TRIM_LEFT|TRIM_RIGHT)
235 local char *trim(char *string, size_t length, char what, int where)
236 {
237 if (where & TRIM_RIGHT) {
238 while (length-- && (string[length] == what)) {
239 string[length] = NUL;
240 }
241 }
242 if (where & TRIM_LEFT) {
243 while (*string == what) {
244 ++string;
245 }
246 }
247 return string;
248 }
249
250 local int strmatch(const char *match, const char *string, const char **begin, const char **end)
251 {
252 *begin = *end = NULL;
253
254 while (*match && *string)
255 {
256 switch (*match)
257 {
258 case '*':
259 while (*match == '*' || *match == '?') {
260 ++match;
261 }
262
263 if (!*begin) {
264 *begin = string;
265 }
266
267 if (!*match) {
268 *end = string + strlen(string);
269 return 1;
270 }
271
272 if (!(string = strchr(string, *match))) {
273 *end = string;
274 return 0;
275 }
276 break;
277
278 case '?':
279 if (!*begin) {
280 *begin = string;
281 }
282 ++string;
283 ++match;
284 break;
285
286 default:
287 if (*match == *string) {
288 if (!*begin) {
289 *begin = string;
290 }
291 ++match;
292 } else {
293 if (*begin) {
294 *end = string - 1;
295 return 0;
296 }
297 }
298 ++string;
299 break;
300 }
301 }
302
303 *end = string;
304 return 1;
305 }
306
307 local char *struniqchr(char *string, char uniq)
308 {
309 char *ptr = string;
310
311 while (ptr[0]) {
312 if (ptr[0] == uniq && ptr[1] == uniq) {
313 char *pos = &ptr[1];
314
315 for (; pos[1] == uniq; ++pos);
316 for (; pos[0]; ++pos) {
317 pos[0] = pos[1];
318 }
319 }
320 ++ptr;
321 }
322
323 return string;
324 }
325
326 local char *domaintree_host(apr_pool_t *pool, MDT_CNF *DT, const char *host_name)
327 {
328 size_t len;
329 char *port, *host;
330
331 if (EMPTY(host_name)) {
332 ap_log_error(DT_LOG_WRN "no host/server name");
333 return NULL;
334 }
335
336 /* copy hostname */
337 host = apr_pstrdup(pool, host_name);
338
339 /* check for :NN port */
340 if ((port = strchr(host, ':'))) {
341 len = port - host;
342 *port = NUL;
343 } else {
344 len = strlen(host);
345 }
346
347 /* strip leading & trailing dots */
348 host = trim(host, len, '.', TRIM_BOTH);
349
350 ap_log_error(DT_LOG_DBG "host name = %s for %s", host, host_name);
351
352 return host;
353 }
354
355 local char *domaintree_path(apr_pool_t *pool, MDT_CNF *DT, const char *host_name)
356 {
357 long depth = 0, maxdepth = IF_SET_ELSE(DT->maxdepth, 20);
358 const char *host = host_name;
359 char *path = NULL, *host_ptr;
360
361 while ((host_ptr = strchr(host, '.'))) {
362
363 /* check max depth */
364 if (++depth > maxdepth) {
365 ap_log_error(DT_LOG_ERR "maxdepth exceeded (%ld)", maxdepth);
366 return NULL;
367 }
368
369 /* append part */
370 if (host_ptr - host) {
371
372 /* strip WWW */
373 if ((DT->stripwww > 0) && (depth == 1) && (!strncmp(host, "www.", sizeof("www")))) {
374 ap_log_error(DT_LOG_DBG "strip www");
375 } else {
376 path = apr_pstrcat(pool, apr_pstrndup(pool, host, host_ptr - host), "/", path, NULL);
377 }
378 }
379
380 host = host_ptr + 1;
381 }
382
383 /* append last part if any and duplicate full path */
384 if (*host) {
385 path = apr_pstrcat(pool, host, "/", path, NULL);
386 }
387
388 ap_log_error(DT_LOG_DBG "path name = %s for %s", path, host_name);
389
390 return path;
391 }
392
393 local void domaintree_fake(apr_pool_t *pool, MDT_CNF *DT, char **path)
394 {
395 int i, more;
396 long recurlevel = 0;
397 apr_pool_t *local_pool;
398 const apr_array_header_t *header = apr_table_elts(DT->aliases.faketable);
399 apr_table_entry_t *array = (apr_table_entry_t *) header->elts;
400
401 if (APR_SUCCESS != apr_pool_create(&local_pool, pool)) {
402 return;
403 }
404
405 do {
406 more = 0;
407
408 if (recurlevel++ > DT->aliases.recursion) {
409 ap_log_error(DT_LOG_ERR "maximum alias recursion level (%ld) exceeded! Check if you have recursive definitions of DomainTreeAlias directives.", DT->aliases.recursion);
410 break;
411 }
412
413 for (i = 0; i < header->nelts; ++i) {
414 const char *begin, *end;
415
416 ap_log_error(DT_LOG_DBG "fake test = %s on %s", array[i].key, *path);
417 if (strmatch(array[i].key, *path, &begin, &end)) {
418 ap_log_error(DT_LOG_DBG "fake done = %s (%s <> %s)", *path, array[i].key, array[i].val);
419 *path = apr_pstrcat(local_pool, "/", apr_pstrndup(local_pool, *path, begin - *path), "/", array[i].val, "/", end, NULL);
420 more = 1;
421 }
422 }
423 } while (more && (DT->aliases.recursion > 0));
424
425 *path = apr_pstrdup(pool, struniqchr(*path, '/'));
426
427 apr_pool_destroy(local_pool);
428 }
429
430 local int domaintree_test(MDT_CNF *DT, const char *host, int argc, const char **argv)
431 {
432 if (argc) {
433 int i;
434 const char *begin, *end, *host_end = host + strlen(host);
435
436 for (i = 0; i < argc; ++i) {
437 ap_log_error(DT_LOG_DBG "host test = %s <> %s", argv[i], host);
438 if (strmatch(argv[i], host, &begin, &end) && begin == host && end == host_end) {
439 ap_log_error(DT_LOG_DBG "test done = %s by %s", host, argv[i]);
440 return 1;
441 }
442 }
443 }
444 return 0;
445 }
446
447 /* }}} */
448 /* {{{ Hooks */
449
450 static STATUS domaintree_hook_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
451 {
452 ap_add_version_component(pconf, "MDT/" VERSION);
453 return OK;
454 }
455
456 static STATUS domaintree_hook_translate_name(request_rec *r)
457 {
458 MDT_CNF *DT;
459 char *host, *path, *docroot;
460
461 if ((!(DT = GET_MDT_CNF(r->server))) || (DT->enabled < 1)) {
462 return DECLINED;
463 }
464
465 #if DBG
466 ap_log_error(DT_LOG_DBG "processid = %d", (int) getpid());
467 #endif
468
469 /* get a usable host name */
470 if (!(host = domaintree_host(r->pool, DT, ap_get_server_name(r)))) {
471 return DECLINED;
472 }
473
474 /* ignore? */
475 if (domaintree_test(DT, host, DT->ignore->nelts, (const char **) DT->ignore->elts)) {
476 return DECLINED;
477 }
478
479 /* forbid? */
480 if (domaintree_test(DT, host, DT->forbid->nelts, (const char **) DT->forbid->elts)) {
481 return HTTP_FORBIDDEN;
482 }
483
484 /* check cache */
485 if ((DT->dircache.clim < 1) || (!(path = domaintree_cache_get(DT, r->request_time, host)))) {
486 /* build path */
487 if (!(path = domaintree_path(r->pool, DT, host))) {
488 return DECLINED;
489 }
490
491 /* apply any aliases */
492 if (apr_table_elts(DT->aliases.faketable)->nelts) {
493 domaintree_fake(r->pool, DT, &path);
494 }
495
496 /* add to cache */
497 if (DT->dircache.clim > 0) {
498 domaintree_cache_set(DT, r->request_time, host, path);
499 }
500 }
501
502 /* compose virtual docroot */
503 docroot = struniqchr(apr_pstrcat(r->pool, DT->prefix, "/", path, "/", DT->suffix, "/", NULL), '/');
504
505 /* stat docroot */
506 if (DT->statroot > 0) {
507 apr_finfo_t sb;
508
509 switch (apr_stat(&sb, docroot, APR_FINFO_MIN, r->pool)) {
510 case APR_SUCCESS:
511 case APR_INCOMPLETE:
512 ap_log_error(DT_LOG_DBG "stat path = %s (success)", docroot);
513 break;
514
515 default:
516 ap_log_error(DT_LOG_DBG "stat path = %s (failure)", docroot);
517 return DECLINED;
518 }
519 }
520
521 /* set virtual docroot */
522 apr_table_set(r->subprocess_env, "VIRTUAL_DOCUMENT_ROOT", docroot);
523
524 /* done */
525 r->canonical_filename = "";
526 r->filename = apr_pstrcat(r->pool, docroot, EMPTY(r->uri) ? NULL : ('/' == *r->uri ? r->uri + 1 : r->uri), NULL);
527
528 ap_log_error(DT_LOG_DBG "path done = %s", r->filename);
529
530 return OK;
531 }
532
533 static void domaintree_hooks(apr_pool_t *pool)
534 {
535 static const char * const pre[] = {"mod_alias.c", "mod_userdir.c", NULL};
536
537 ap_hook_post_config(domaintree_hook_post_config, NULL, NULL, APR_HOOK_MIDDLE);
538 ap_hook_translate_name(domaintree_hook_translate_name, pre, NULL, APR_HOOK_FIRST);
539 }
540
541 /* }}} */
542 /* {{{ Configuration */
543
544 static void *domaintree_create_srv(apr_pool_t *p, server_rec *s)
545 {
546 MDT_CNF *DT= (MDT_CNF *) apr_palloc(p, sizeof(MDT_CNF));
547
548 DT->server = s;
549 DT->enabled = -1;
550 DT->stripwww = -1;
551 DT->statroot = -1;
552 DT->maxdepth = -1;
553
554 DT->prefix = "/var/www";
555 DT->suffix = "public_html";
556
557 DT->ignore = apr_array_make(p, 0, sizeof(char *));
558 DT->forbid = apr_array_make(p, 0, sizeof(char *));
559
560 DT->aliases.recursion = -1;
561 DT->aliases.faketable = apr_table_make(p, 0);
562
563 DT->dircache.clim = -1;
564 DT->dircache.hmap = apr_hash_make(p);
565 apr_pool_create(&DT->dircache.pool, p);
566 apr_global_mutex_create(&DT->dircache.lock, __FILE__, APR_LOCK_DEFAULT, p);
567 #if DBG
568 fprintf(stderr, "MDT: cfg create %p\n", DT);
569 #endif
570 return DT;
571 }
572
573 static void *domaintree_merge_srv(apr_pool_t *p, void *old_cfg_ptr, void *new_cfg_ptr)
574 {
575 MDT_CNF *old_cfg = (MDT_CNF *) old_cfg_ptr, *new_cfg = (MDT_CNF *) new_cfg_ptr;
576 MDT_CNF *DT = (MDT_CNF *) apr_palloc(p, sizeof(MDT_CNF));
577
578 DT->server = new_cfg->server;
579 DT->enabled = IF_SET_ELSE(new_cfg->enabled, old_cfg->enabled);
580 DT->stripwww = IF_SET_ELSE(new_cfg->stripwww, old_cfg->stripwww);
581 DT->statroot = IF_SET_ELSE(new_cfg->statroot, old_cfg->statroot);
582 DT->maxdepth = IF_SET_ELSE(new_cfg->maxdepth, old_cfg->maxdepth);
583
584 DT->prefix = EMPTY(new_cfg->prefix) ? EMPTY(old_cfg->prefix) ? "/var/www" : old_cfg->prefix : new_cfg->prefix;
585 DT->suffix = EMPTY(new_cfg->suffix) ? EMPTY(old_cfg->suffix) ? "public_html" : old_cfg->suffix : new_cfg->suffix;
586
587 DT->ignore = apr_array_append(p, new_cfg->ignore, old_cfg->ignore);
588 DT->forbid = apr_array_append(p, new_cfg->forbid, old_cfg->forbid);
589
590 DT->aliases.recursion = IF_SET_ELSE(new_cfg->aliases.recursion, old_cfg->aliases.recursion);
591 DT->aliases.faketable = apr_table_overlay(p, new_cfg->aliases.faketable, old_cfg->aliases.faketable);
592
593 DT->dircache.clim = IF_SET_ELSE(new_cfg->dircache.clim, old_cfg->dircache.clim);
594 DT->dircache.hmap = apr_hash_overlay(p, new_cfg->dircache.hmap, old_cfg->dircache.hmap);
595 apr_global_mutex_create(&new_cfg->dircache.lock, __FILE__, APR_LOCK_DEFAULT, p);
596 #if DBG
597 fprintf(stderr, "MDT: cfg merge %p + %p = %p\n", old_cfg, new_cfg, DT);
598 #endif
599 return DT;
600 }
601
602 static const char *domaintree_init_enable(cmd_parms *cmd, void *conf, int flag)
603 {
604 GET_MDT_CNF(cmd->server)->enabled = flag;
605 return NULL;
606 }
607
608 static const char *domaintree_init_stripwww(cmd_parms *cmd, void *conf, int flag)
609 {
610 GET_MDT_CNF(cmd->server)->stripwww = flag;
611 return NULL;
612 }
613
614 static const char *domaintree_init_statroot(cmd_parms *cmd, void *conf, int flag)
615 {
616 GET_MDT_CNF(cmd->server)->statroot = flag;
617 return NULL;
618 }
619
620 static const char *domaintree_init_prefix(cmd_parms *cmd, void *conf, const char *prefix)
621 {
622 GET_MDT_CNF(cmd->server)->prefix = EMPTY(prefix) ? "/" : trim(apr_pstrdup(cmd->pool, prefix), strlen(prefix), '/', TRIM_RIGHT);
623 return NULL;
624 }
625
626 static const char *domaintree_init_suffix(cmd_parms *cmd, void *conf, const char *suffix)
627 {
628 GET_MDT_CNF(cmd->server)->suffix = EMPTY(suffix) ? "" : trim(apr_pstrdup(cmd->pool, suffix), strlen(suffix), '/', TRIM_BOTH);
629 return NULL;
630 }
631
632 static const char *domaintree_init_maxdepth(cmd_parms *cmd, void *conf, const char *max_depth)
633 {
634 long depth;
635
636 if ((depth = atol(max_depth))) {
637 if (depth >= 0L) {
638 GET_MDT_CNF(cmd->server)->maxdepth = depth;
639 } else {
640 return "Maximum DomainTree depth cannot be negative.";
641 }
642 }
643
644 return NULL;
645 }
646
647 static const char *domaintree_init_aliasrecursion(cmd_parms *cmd, void *conf, const char *alias_recursion)
648 {
649 long recursion;
650
651 if ((recursion = atol(alias_recursion))) {
652 if (recursion >= 0L) {
653 GET_MDT_CNF(cmd->server)->aliases.recursion = recursion;
654 } else {
655 return "DomainTree alias recursion cannot be negative.";
656 }
657 }
658
659 return NULL;
660 }
661
662 static const char *domaintree_init_alias(cmd_parms *cmd, void *conf, const char *fake, const char *real)
663 {
664 char *f = strtr(apr_pstrdup(cmd->pool, fake), '.', '/'), *r = strtr(apr_pstrdup(cmd->pool, real), '.', '/');
665
666 apr_table_set(GET_MDT_CNF(cmd->server)->aliases.faketable, trim(f, strlen(f), '/', TRIM_BOTH), trim(r, strlen(r), '/', TRIM_BOTH));
667
668 return NULL;
669 }
670
671 static const char *domaintree_init_cache(cmd_parms *cmd, void *conf, const char *cache)
672 {
673 long limit;
674
675 if ((limit = atol(cache))) {
676 if (limit >= 0L) {
677 GET_MDT_CNF(cmd->server)->dircache.clim = limit;
678 } else {
679 return "DomainTree cache limit cannot be negative.";
680 }
681 }
682
683 return NULL;
684 }
685
686 static const char *domaintree_init_ignore(cmd_parms *cmd, void *conf, const char *ignore)
687 {
688 *((char **) apr_array_push(GET_MDT_CNF(cmd->server)->ignore)) = trim(apr_pstrdup(cmd->pool, ignore), strlen(ignore), '.', TRIM_BOTH);
689 return NULL;
690 }
691
692 static const char *domaintree_init_forbid(cmd_parms *cmd, void *conf, const char *forbid)
693 {
694 *((char **) apr_array_push(GET_MDT_CNF(cmd->server)->forbid)) = trim(apr_pstrdup(cmd->pool, forbid), strlen(forbid), '.', TRIM_BOTH);
695 return NULL;
696 }
697
698 /* }}} */
699 /* {{{ Commands */
700
701 static command_rec domaintree_commands[] = {
702 AP_INIT_FLAG(
703 "DomainTreeEnabled", domaintree_init_enable, NULL, RSRC_CONF,
704 "Turn the module on or off."
705 ),
706
707 AP_INIT_FLAG(
708 "DomainTreeStripWWW", domaintree_init_stripwww, NULL, RSRC_CONF,
709 "Strip leading www from host. (default On)"
710 ),
711
712 AP_INIT_FLAG(
713 "DomainTreeStatRoot", domaintree_init_statroot, NULL, RSRC_CONF,
714 "Wheter to check for the evaluated virtual document root with a stat call. (default Off)"
715 ),
716
717 AP_INIT_TAKE1(
718 "DomainTreePrefix", domaintree_init_prefix, NULL, RSRC_CONF,
719 "DomainTree path prefix. (default /var/www) Do not forget the leading slash!"
720 ),
721
722 AP_INIT_TAKE1(
723 "DomainTreeSuffix", domaintree_init_suffix, NULL, RSRC_CONF,
724 "DomainTree path suffix. (default public_html)"
725 ),
726
727 AP_INIT_TAKE1(
728 "DomainTreeMaxdepth", domaintree_init_maxdepth, NULL, RSRC_CONF,
729 "DomainTree max path depth. (default 20)"
730 ),
731
732 AP_INIT_TAKE1(
733 "DomainTreeAliasRecursion", domaintree_init_aliasrecursion, NULL, RSRC_CONF,
734 "Whether (and how often at the maximum) DomainTree should walk recursively "
735 "through the aliases list as long as matching aliases are found. (default: 0 = turned off)"
736 ),
737
738 AP_INIT_TAKE2(
739 "DomainTreeAlias", domaintree_init_alias, NULL, RSRC_CONF,
740 "DomainTree aliases; e.g. DomainTreeAlias com/example/tickets com/example/support (dots or slashes equal)"
741 ),
742
743 AP_INIT_TAKE1(
744 "DomainTreeCache", domaintree_init_cache, NULL, RSRC_CONF,
745 "DomainTree server-wide host to directory cache; specify how many cache entries to allow (default: 0 = turned off)"
746 ),
747
748 AP_INIT_ITERATE(
749 "DomainTreeIgnore", domaintree_init_ignore, NULL, RSRC_CONF,
750 "DomainTree ignored hosts; uses the same matching alogrithm like DomainTreeAlias"
751 ),
752
753 AP_INIT_ITERATE(
754 "DomainTreeForbid", domaintree_init_forbid, NULL, RSRC_CONF,
755 "DomanTree forbidden hosts; uses the same matching algorithm like DomainTreeAlias"
756 ),
757
758 { NULL }
759 };
760
761 /* }}} */
762 /* {{{ Module Administrativa */
763
764 module AP_MODULE_DECLARE_DATA domaintree_module = {
765 STANDARD20_MODULE_STUFF,
766 NULL, /* create per-dir */
767 NULL, /* merge per-dir */
768 domaintree_create_srv, /* create per-server */
769 domaintree_merge_srv, /* merge per-server */
770 domaintree_commands, /* config commands */
771 domaintree_hooks /* hooks */
772 };
773
774 /* }}} */
775
776 /*
777 * Local variables:
778 * tab-width: 4
779 * c-basic-offset: 4
780 * End:
781 * vim600: noet sw=4 ts=4 fdm=marker
782 * vim<600: noet sw=4 ts=4
783 */