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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * mod_vhost_alias.c: support for dynamically configured mass virtual hosting
20 * Copyright (c) 1998-1999 Demon Internet Ltd.
22 * This software was submitted by Demon Internet to the Apache Software Foundation
23 * in May 1999. Future revisions and derivatives of this source code
24 * must acknowledge Demon Internet as the original contributor of
25 * this module. All other licensing and usage conditions are those
26 * of the Apache Software Foundation.
28 * Originally written by Tony Finch <fanf@demon.net> <dot@dotat.at>.
30 * Implementation ideas were taken from mod_alias.c. The overall
31 * concept is derived from the OVERRIDE_DOC_ROOT/OVERRIDE_CGIDIR
32 * patch to Apache 1.3b3 and a similar feature in Demon's thttpd,
33 * both written by James Grinter <jrg@blodwen.demon.co.uk>.
37 #include "apr_strings.h"
38 #include "apr_hooks.h"
41 #define APR_WANT_STRFUNC
45 #include "http_config.h"
46 #include "http_core.h"
47 #include "http_request.h" /* for ap_hook_translate_name */
50 module AP_MODULE_DECLARE_DATA vhost_alias_module;
54 * basic configuration things
55 * we abbreviate "mod_vhost_alias" to "mva" for shorter names
59 VHOST_ALIAS_UNSET, VHOST_ALIAS_NONE, VHOST_ALIAS_NAME, VHOST_ALIAS_IP
63 * Per-server module config record.
65 typedef struct mva_sconf_t {
68 mva_mode_e doc_root_mode;
69 mva_mode_e cgi_root_mode;
72 static void *mva_create_server_config(apr_pool_t *p, server_rec *s)
76 conf = (mva_sconf_t *) apr_pcalloc(p, sizeof(mva_sconf_t));
77 conf->doc_root = NULL;
78 conf->cgi_root = NULL;
79 conf->doc_root_mode = VHOST_ALIAS_UNSET;
80 conf->cgi_root_mode = VHOST_ALIAS_UNSET;
84 static void *mva_merge_server_config(apr_pool_t *p, void *parentv, void *childv)
86 mva_sconf_t *parent = (mva_sconf_t *) parentv;
87 mva_sconf_t *child = (mva_sconf_t *) childv;
90 conf = (mva_sconf_t *) apr_pcalloc(p, sizeof(*conf));
91 if (child->doc_root_mode == VHOST_ALIAS_UNSET) {
92 conf->doc_root_mode = parent->doc_root_mode;
93 conf->doc_root = parent->doc_root;
96 conf->doc_root_mode = child->doc_root_mode;
97 conf->doc_root = child->doc_root;
99 if (child->cgi_root_mode == VHOST_ALIAS_UNSET) {
100 conf->cgi_root_mode = parent->cgi_root_mode;
101 conf->cgi_root = parent->cgi_root;
104 conf->cgi_root_mode = child->cgi_root_mode;
105 conf->cgi_root = child->cgi_root;
112 * These are just here to tell us what vhost_alias_set should do.
113 * We don't put anything into them; we just use the cell addresses.
115 static int vhost_alias_set_doc_root_ip,
116 vhost_alias_set_cgi_root_ip,
117 vhost_alias_set_doc_root_name,
118 vhost_alias_set_cgi_root_name;
120 static const char *vhost_alias_set(cmd_parms *cmd, void *dummy, const char *map)
123 mva_mode_e mode, *pmode;
127 conf = (mva_sconf_t *) ap_get_module_config(cmd->server->module_config,
128 &vhost_alias_module);
129 /* there ought to be a better way of doing this */
130 if (&vhost_alias_set_doc_root_ip == cmd->info) {
131 mode = VHOST_ALIAS_IP;
132 pmap = &conf->doc_root;
133 pmode = &conf->doc_root_mode;
135 else if (&vhost_alias_set_cgi_root_ip == cmd->info) {
136 mode = VHOST_ALIAS_IP;
137 pmap = &conf->cgi_root;
138 pmode = &conf->cgi_root_mode;
140 else if (&vhost_alias_set_doc_root_name == cmd->info) {
141 mode = VHOST_ALIAS_NAME;
142 pmap = &conf->doc_root;
143 pmode = &conf->doc_root_mode;
145 else if (&vhost_alias_set_cgi_root_name == cmd->info) {
146 mode = VHOST_ALIAS_NAME;
147 pmap = &conf->cgi_root;
148 pmode = &conf->cgi_root_mode;
151 return "INTERNAL ERROR: unknown command info";
154 if (!ap_os_is_path_absolute(cmd->pool, map)) {
155 if (strcasecmp(map, "none")) {
156 return "format string must be an absolute path, or 'none'";
159 *pmode = VHOST_ALIAS_NONE;
169 /* we just found a '%' */
170 if (*p == 'p' || *p == '%') {
179 if (apr_isdigit(*p)) {
183 return "syntax error in format string";
189 /* do we end here? */
199 if (apr_isdigit(*p)) {
203 return "syntax error in format string";
215 static const command_rec mva_commands[] =
217 AP_INIT_TAKE1("VirtualScriptAlias", vhost_alias_set,
218 &vhost_alias_set_cgi_root_name, RSRC_CONF,
219 "how to create a ScriptAlias based on the host"),
220 AP_INIT_TAKE1("VirtualDocumentRoot", vhost_alias_set,
221 &vhost_alias_set_doc_root_name, RSRC_CONF,
222 "how to create the DocumentRoot based on the host"),
223 AP_INIT_TAKE1("VirtualScriptAliasIP", vhost_alias_set,
224 &vhost_alias_set_cgi_root_ip, RSRC_CONF,
225 "how to create a ScriptAlias based on the host"),
226 AP_INIT_TAKE1("VirtualDocumentRootIP", vhost_alias_set,
227 &vhost_alias_set_doc_root_ip, RSRC_CONF,
228 "how to create the DocumentRoot based on the host"),
234 * This really wants to be a nested function
235 * but C is too feeble to support them.
237 static APR_INLINE void vhost_alias_checkspace(request_rec *r, char *buf,
238 char **pdest, int size)
240 /* XXX: what if size > HUGE_STRING_LEN? */
241 if (*pdest + size > buf + HUGE_STRING_LEN) {
244 r->filename = apr_pstrcat(r->pool, r->filename, buf, NULL);
247 r->filename = apr_pstrdup(r->pool, buf);
253 static void vhost_alias_interpolate(request_rec *r, const char *name,
254 const char *map, const char *uri)
257 enum { MAXDOTS = 19 };
258 const char *dots[MAXDOTS+1];
261 char buf[HUGE_STRING_LEN];
264 int N, M, Np, Mp, Nd, Md;
265 const char *start, *end;
270 dots[ndots++] = name-1; /* slightly naughty */
271 for (p = name; *p; ++p){
272 if (*p == '.' && ndots < MAXDOTS) {
284 /* normal characters */
285 vhost_alias_checkspace(r, buf, &dest, 1);
286 last = *dest++ = *map++;
289 /* we are in a format specifier */
291 /* can't be a slash */
296 vhost_alias_checkspace(r, buf, &dest, 1);
303 /* no. of decimal digits in a short plus one */
304 vhost_alias_checkspace(r, buf, &dest, 7);
305 dest += apr_snprintf(dest, 7, "%d", ap_get_server_port(r));
308 /* deal with %-N+.-M+ -- syntax is already checked */
309 N = M = 0; /* value */
310 Np = Mp = 0; /* is there a plus? */
311 Nd = Md = 0; /* is there a dash? */
312 if (*map == '-') ++map, Nd = 1;
314 if (*map == '+') ++map, Np = 1;
325 /* note that N and M are one-based indices, not zero-based */
326 start = dots[0]+1; /* ptr to the first character */
327 end = dots[ndots]; /* ptr to the character after the last one */
341 start = dots[ndots-N]+1;
343 end = dots[ndots-N+1];
347 if (M > end - start) {
364 vhost_alias_checkspace(r, buf, &dest, end - start);
365 for (p = start; p < end; ++p) {
366 *dest++ = apr_tolower(*p);
370 /* no double slashes */
376 r->filename = apr_pstrcat(r->pool, r->filename, buf, uri, NULL);
379 r->filename = apr_pstrcat(r->pool, buf, uri, NULL);
383 static int mva_translate(request_rec *r)
386 const char *name, *map, *uri;
390 conf = (mva_sconf_t *) ap_get_module_config(r->server->module_config,
391 &vhost_alias_module);
393 if (conf->cgi_root) {
394 cgi = strstr(r->uri, "cgi-bin/");
395 if (cgi && (cgi != r->uri + strspn(r->uri, "/"))) {
400 mode = conf->cgi_root_mode;
401 map = conf->cgi_root;
402 uri = cgi + strlen("cgi-bin");
404 else if (r->uri[0] == '/') {
405 mode = conf->doc_root_mode;
406 map = conf->doc_root;
413 if (mode == VHOST_ALIAS_NAME) {
414 name = ap_get_server_name(r);
416 else if (mode == VHOST_ALIAS_IP) {
417 name = r->connection->local_ip;
423 /* ### There is an optimization available here to determine the
424 * absolute portion of the path from the server config phase,
425 * through the first % segment, and note that portion of the path
426 * canonical_path buffer.
428 r->canonical_filename = "";
429 vhost_alias_interpolate(r, name, map, uri);
432 /* see is_scriptaliased() in mod_cgi */
433 r->handler = "cgi-script";
434 apr_table_setn(r->notes, "alias-forced-type", r->handler);
440 static void register_hooks(apr_pool_t *p)
442 static const char * const aszPre[]={ "mod_alias.c","mod_userdir.c",NULL };
444 ap_hook_translate_name(mva_translate, aszPre, NULL, APR_HOOK_MIDDLE);
447 module AP_MODULE_DECLARE_DATA vhost_alias_module =
449 STANDARD20_MODULE_STUFF,
450 NULL, /* dir config creater */
451 NULL, /* dir merger --- default is to override */
452 mva_create_server_config, /* server config */
453 mva_merge_server_config, /* merge server configs */
454 mva_commands, /* command apr_table_t */
455 register_hooks /* register hooks */