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 */