2 * mod_domaintree.c - Apache2
6 * Copyright 2005 Michael Wallner <mike@iworks.at
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * DomainTreeEnabled On
23 * DomainTreeMaxdepth 25
24 * DomainTreeStripWWW On
25 * DomainTreePrefix /sites
26 * DomainTreeSuffix /html
27 * DomainTreeAliasRecursion Off
28 * DomainTreeAlias /??/exmaple /com/exmaple
29 * DomainTreeAlias /???/example /com/example
30 * DomainTreeAlais /*one/ /anyone/
50 #define MODULE "mod_domaintree"
51 #define AUTHOR "mike@php.net"
57 #include "http_config.h"
60 #include "http_core.h"
64 #include "http_protocol.h"
65 #include "http_request.h"
71 #include "apr_strings.h"
73 #define APR_WANT_STRFUNC
77 /* {{{ domaintree_module */
79 module AP_MODULE_DECLARE_DATA domaintree_module
;
82 /* {{{ Macros & Types */
84 #define MOD_DT_CNF domaintree_conf
85 #define MOD_DT_PTR (&domaintree_module)
88 #define EMPTY(str) ((str == NULL) || (*(str) == NUL))
90 #define DT_LOG_ERR ap_log_error(APLOG_MARK, APLOG_ERR, APR_SUCCESS, DT->server,
91 #define DT_LOG_WRN ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, DT->server,
92 #define DT_LOG_DBG ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, DT->server,
98 apr_hash_t
*hashtable
;
112 struct domaintree_entry
{
114 APR_RING_ENTRY(domaintree_entry
) link
;
116 APR_RING_HEAD(domaintree
, domaintree_entry
);
121 static APR_INLINE
char *strtr(char *string
, char from
, char to
)
126 while ((ptr
= strchr(ptr
, from
))) {
133 static APR_INLINE
char *trim(char *string
, size_t length
, char what
, int l
, int r
)
136 while (length
-- && (string
[length
] == what
)) {
137 string
[length
] = NUL
;
141 while (*string
== what
) {
148 static APR_INLINE
char *strcase(char *string
, int case_type
)
151 # define CASE_LOWER 1
154 # define CASE_UPPER 2
179 static APR_INLINE
int strmatch(char *match
, char *string
, char **begin
, char **end
)
181 *begin
= *end
= NULL
;
188 while (*match
== '*' || *match
== '?') {
197 *end
= string
+ strlen(string
);
201 if (!(string
= strchr(string
, *match
))) {
216 if (*match
== *string
) {
236 static APR_INLINE
char *struniqchr(char *string
, char uniq
)
241 if (*ptr
== uniq
&& *(ptr
+ 1) == uniq
) {
244 while (*(pos
+ 1) == uniq
) {
248 memmove(ptr
, pos
, strlen(pos
) + 1);
256 static APR_INLINE
char *domaintree_host(apr_pool_t
*pool
, MOD_DT_CNF
*DT
, const char *name
)
260 "DomainTree: no host/server name"
265 char *port
, *ptr
, *host
;
267 ptr
= host
= apr_pstrdup(pool
, name
);
270 "DomainTree: host name = %s", host
273 /* check for :NN port */
274 if ((port
= strchr(ptr
, ':'))) {
280 /* strip leading & trailing dots, then lowercase */
281 ptr
= host
= strcase(trim(ptr
, len
, '.', 1, 1), CASE_LOWER
);
284 "DomainTree: sane host = %s", host
291 static APR_INLINE
const char *domaintree_elem(apr_pool_t
*pool
, struct domaintree
*tree
, const char *name
, size_t length
)
293 struct domaintree_entry
*elem
= apr_palloc(pool
, sizeof(struct domaintree_entry
));
295 APR_RING_ELEM_INIT(elem
, link
);
296 APR_RING_INSERT_HEAD(tree
, elem
, domaintree_entry
, link
);
298 return elem
->name
= apr_pstrndup(pool
, name
, length
);
301 static APR_INLINE
struct domaintree
*domaintree_tree(apr_pool_t
*pool
, MOD_DT_CNF
*DT
, char *host
)
304 char *host_ptr
= host
;
305 struct domaintree
*tree
= apr_palloc(pool
, sizeof(struct domaintree
));
307 APR_RING_INIT(tree
, domaintree_entry
, link
);
309 while ((host_ptr
= strchr(host
, '.'))) {
311 /* check max depth */
312 if (++depth
> DT
->maxdepth
) {
314 "DomainTree: maxdepth exceeded = %s", host
320 if (host_ptr
- host
) {
323 if (DT
->stripwww
&& (depth
== 1) && (!strncmp(host
, "www.", sizeof("www")))) {
325 "DomainTree: stripping www."
329 "DomainTree: host part (%d) = %s", depth
- 1,
330 domaintree_elem(pool
, tree
, host
, host_ptr
- host
)
338 /* append last part */
341 "DomainTree: host part (%d) = %s", depth
,
342 domaintree_elem(pool
, tree
, host
, strlen(host
))
349 static APR_INLINE
char *domaintree_path(apr_pool_t
*pool
, MOD_DT_CNF
*DT
, struct domaintree
*tree
)
351 struct domaintree_entry
*elem
;
354 APR_RING_FOREACH(elem
, tree
, domaintree_entry
, link
) {
355 path
= apr_pstrcat(pool
, path
, "/", elem
->name
, NULL
);
361 static APR_INLINE
void domaintree_fake(apr_pool_t
*pool
, MOD_DT_CNF
*DT
, char **path
)
364 apr_hash_index_t
*idx
;
365 size_t recurlevel
= 0;
370 if (recurlevel
++ > DT
->aliases
.recursion
) {
372 "DomainTree: maximum alias recursion level (%d) exceeded! "
373 "Check if you have recursive definitions of DomainTreeAlias directives.",
374 DT
->aliases
.recursion
379 for (idx
= apr_hash_first(pool
, DT
->aliases
.hashtable
); idx
; idx
= apr_hash_next(idx
)) {
380 char *fake
, *real
, *begin
, *end
;
382 apr_hash_this(idx
, (const void **) &fake
, NULL
, (void **) &real
);
385 "DomainTree: fake test %s on %s", fake
, *path
388 if (strmatch(fake
, *path
, &begin
, &end
)) {
389 *path
= apr_pstrcat(pool
, "/", apr_pstrndup(pool
, *path
, begin
- *path
), "/", real
, "/", end
, NULL
);
390 struniqchr(*path
, '/');
393 "DomainTree: fake done %s<>%s = %s", fake
, real
, *path
399 } while (more
&& DT
->aliases
.recursion
);
405 static STATUS
domaintree_hook_post_config(apr_pool_t
*pconf
, apr_pool_t
*plog
, apr_pool_t
*ptemp
, server_rec
*s
)
407 ap_add_version_component(pconf
, MODULE
"/" VERSION
);
411 static STATUS
domaintree_hook_translate_name(request_rec
*r
)
413 MOD_DT_CNF
*DT
= NULL
;
414 struct domaintree
*tree
;
417 DT
= ap_get_module_config(r
->server
->module_config
, MOD_DT_PTR
);
418 if ((!DT
) || (!DT
->enabled
)) {
422 /* get a usable host name */
423 if (!(host
= domaintree_host(r
->pool
, DT
, ap_get_server_name(r
)))) {
427 /* build domain tree */
428 if (!(tree
= domaintree_tree(r
->pool
, DT
, host
))) {
433 if (!(path
= domaintree_path(r
->pool
, DT
, tree
))) {
437 /* apply any aliases */
438 domaintree_fake(r
->pool
, DT
, &path
);
441 r
->canonical_filename
= "";
442 r
->filename
= apr_pstrcat(r
->pool
, DT
->prefix
, "/", path
, "/", DT
->suffix
, r
->uri
, NULL
);
443 struniqchr(r
->filename
, '/');
446 "DomainTree: path done = %s", r
->filename
452 static void domaintree_hooks(apr_pool_t
*pool
)
454 ap_hook_post_config(domaintree_hook_post_config
, NULL
, NULL
, APR_HOOK_MIDDLE
);
455 ap_hook_translate_name(domaintree_hook_translate_name
, NULL
, NULL
, APR_HOOK_MIDDLE
);
459 /* {{{ Configuration */
461 static void *domaintree_create_srv(apr_pool_t
*p
, server_rec
*s
)
465 DT
= (MOD_DT_CNF
*) apr_palloc(p
, sizeof(MOD_DT_CNF
));
472 DT
->prefix
= "/var/www";
473 DT
->suffix
= "public_html";
475 DT
->aliases
.hashtable
= apr_hash_make(p
);
476 DT
->aliases
.recursion
= 0;
481 static const char *domaintree_enable(cmd_parms
*cmd
, void *conf
, int flag
)
485 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
491 static const char *domaintree_stripwww(cmd_parms
*cmd
, void *conf
, int flag
)
495 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
501 static const char *domaintree_prefix(cmd_parms
*cmd
, void *conf
, const char *prefix
)
505 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
506 DT
->prefix
= EMPTY(prefix
) ? "/" : trim(apr_pstrdup(cmd
->pool
, prefix
), strlen(prefix
), '/', 0, 1);
511 static const char *domaintree_suffix(cmd_parms
*cmd
, void *conf
, const char *suffix
)
515 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
516 DT
->suffix
= EMPTY(suffix
) ? "" : trim(apr_pstrdup(cmd
->pool
, suffix
), strlen(suffix
), '/', 1, 1);
521 static const char *domaintree_maxdepth(cmd_parms
*cmd
, void *conf
, const char *max_depth
)
525 if ((depth
= atol(max_depth
))) {
528 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
529 DT
->maxdepth
= (size_t) depth
;
531 return "Maximum DomainTree depth cannot be negative.";
538 static const char *domaintree_aliasrecursion(cmd_parms
*cmd
, void *conf
, const char *alias_recursion
)
542 if ((recursion
= atol(alias_recursion
))) {
543 if (recursion
> 0L) {
545 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
546 DT
->aliases
.recursion
= (size_t) recursion
;
548 return "DomainTree alias recursion cannot be negative.";
555 static const char *domaintree_alias(cmd_parms
*cmd
, void *conf
, const char *fake
, const char *real
)
558 char *f
= strtr(apr_pstrdup(cmd
->pool
, fake
), '.', '/'), *r
= strtr(apr_pstrdup(cmd
->pool
, real
), '.', '/');
560 DT
= ap_get_module_config(cmd
->server
->module_config
, MOD_DT_PTR
);
561 apr_hash_set(DT
->aliases
.hashtable
, trim(f
, strlen(f
), '/', 1, 1), APR_HASH_KEY_STRING
, trim(r
, strlen(r
), '/', 1, 1));
570 static command_rec domaintree_commands
[] = {
572 "DomainTreeEnabled", domaintree_enable
, NULL
, RSRC_CONF
,
573 "Turn the module on or off."
577 "DomainTreeStripWWW", domaintree_stripwww
, NULL
, RSRC_CONF
,
578 "Strip leading www from host. (default On)"
582 "DomainTreePrefix", domaintree_prefix
, NULL
, RSRC_CONF
,
583 "DomainTree path prefix. (default /var/www) Do not forget the leading slash!"
587 "DomainTreeSuffix", domaintree_suffix
, NULL
, RSRC_CONF
,
588 "DomainTree path suffix. (default public_html)"
592 "DomainTreeMaxdepth", domaintree_maxdepth
, NULL
, RSRC_CONF
,
593 "DomainTree max path depth. (default 20)"
597 "DomainTreeAliasRecursion", domaintree_aliasrecursion
, NULL
, RSRC_CONF
,
598 "Whether (and how often at the maximum) DomainTree should walk recursively "
599 "through the aliases list as long as matching aliases are found. (Default: 0 = turned off)"
603 "DomainTreeAlias", domaintree_alias
, NULL
, RSRC_CONF
,
604 "DomainTree aliases; e.g. DomainTreeAlias com/example/tickets com/example/support (dots or slashes equal)"
611 /* {{{ Module Administrativa */
613 module AP_MODULE_DECLARE_DATA domaintree_module
= {
614 STANDARD20_MODULE_STUFF
,
615 NULL
, /* create per-dir */
616 NULL
, /* merge per-dir */
617 domaintree_create_srv
, /* create per-server */
618 NULL
, /* merge per-server */
619 domaintree_commands
, /* apr_table_t commands */
620 domaintree_hooks
/* hooks */
630 * vim600: noet sw=4 ts=4 fdm=marker
631 * vim<600: noet sw=4 ts=4