add vhost.map action to mod_vhost
parent
c7c1c5cb0e
commit
bc92b6fdcc
|
@ -2,33 +2,55 @@
|
|||
* mod_vhost - virtual hosting
|
||||
*
|
||||
* Description:
|
||||
* mod_vhost offers various ways to implement virtual webhosts
|
||||
* it can map hostnames to document roots or even actions
|
||||
* mod_vhost offers various ways to implement virtual webhosts.
|
||||
* It can map hostnames to document roots or even actions and offers multiple ways to do so.
|
||||
* These ways differ in the flexibility of mapping (what to map and what to map to) as well as performance.
|
||||
*
|
||||
* Setups:
|
||||
* none
|
||||
* Options:
|
||||
* vhost.debug <true|false> - enable debug output
|
||||
* type: boolean
|
||||
* vhost.debug = <true|fast> - enable debug output
|
||||
* Actions:
|
||||
* vhost.simple ("server-root" => string, "docroot" => string, "default" => string)
|
||||
* vhost.simple ("server-root" => string, "docroot" => string, "default" => string);
|
||||
* - builds the document root by concatinating server-root + hostname + docroot
|
||||
* - if the newly build docroot does not exist, repeat with "default" hostname
|
||||
* - not very flexible but fast (use symlinks for some limited flexibility)
|
||||
* vhost.map ["host1": action1, "host2": action2, "default": action0];
|
||||
* - lookup action by using the hostname as the key of the hashtable
|
||||
* - if not found, use default action
|
||||
* - fast and flexible but no matching on hostnames possible
|
||||
* vhost.map_regex ["host1regex": action1, "host2regex": action2, "default": action0];
|
||||
* - lookup action by traversing the list and applying a regex match of the hostname on each entry
|
||||
* - if no match, use default action
|
||||
* - slowest method but the most flexible one
|
||||
* - somewhat optimized internally and automatically to speed up lookup of frequently accessed hosts
|
||||
*
|
||||
* Example config:
|
||||
* vhost.simple ("server-root" => "/var/www/vhosts/", "docroot" => "/pub", "default" => "localhost");
|
||||
* mydom1 {...} mydom2 {...} defaultdom {...}
|
||||
* vhost.map ["dom1.com": mydom1, "dom2.tld": mydom2, "default": defaultdom];
|
||||
* vhost.map_regex ["^(.+\.)?dom1\.com$": mydom1, "^dom2\.(com|net|org)$": mydom2, "default": defaultdom];
|
||||
*
|
||||
* Tip:
|
||||
* You can combine vhost.map and vhost.map_regex to create a reasonably fast and flexible vhost mapping mechanism.
|
||||
* Just use a vhost.map_regex action as the default fallback action in vhost.map.
|
||||
* This way, the expensive vhost.map_regex is only used if the vhost was not found in vhost.map.
|
||||
*
|
||||
* Todo:
|
||||
* - use stat cache (when implemented)
|
||||
* - add vhost.map action
|
||||
* dom1.tld {...} dom2.tld {...} vhost.map ["dom1.tld": dom1.tld, "*.dom1.tld": dom1.tld, "dom2.tld": dom2.tld, "default": dom1.tld];
|
||||
* - split hashtable into hashtable with plain hostnames and array with wildcard hostnames
|
||||
* - hashtable lookup is fast, wildcard matching not => first look in hashtable then in array
|
||||
* - optimize array by ordering it by matches => frequently matched vhosts at the beginning resulting in a better hitrate
|
||||
* - add vhost.map_regex action which maps a hostname to an action using regular expression matching on a list of strings
|
||||
* - normal hashtable lookup not possible, traverse list and apply every regex to the hostname until a match is found
|
||||
* - optimize list by ordering it by number of matches every n seconds
|
||||
* => frequently matched vhosts at the beginning resulting in a better hitrate
|
||||
* - copy list, order the copy, exchange original list and copy
|
||||
* - delete original list (now the copy) before the next optimization run or just overwrite it during the copy step
|
||||
* - reset counter of entries that haven't been matched during the last n hours
|
||||
* - also build a hashtable to cache lookups?
|
||||
* - mod_evhost equivalent?
|
||||
* - add setup actions to control vhost.map_regex caching behaviour
|
||||
*
|
||||
* Author:
|
||||
* Copyright (c) 2008 Thomas Porzelt
|
||||
* Copyright (c) 2009 Thomas Porzelt
|
||||
* License:
|
||||
* MIT, see COPYING file in the lighttpd 2 tree
|
||||
*/
|
||||
|
@ -46,6 +68,13 @@ struct vhost_simple_data {
|
|||
};
|
||||
typedef struct vhost_simple_data vhost_simple_data;
|
||||
|
||||
struct vhost_map_data {
|
||||
plugin *plugin;
|
||||
GHashTable *hash;
|
||||
value *default_action;
|
||||
};
|
||||
typedef struct vhost_map_data vhost_map_data;
|
||||
|
||||
|
||||
static handler_t vhost_simple(vrequest *vr, gpointer param, gpointer *context) {
|
||||
struct stat st;
|
||||
|
@ -169,6 +198,76 @@ static action* vhost_simple_create(server *srv, plugin* p, value *val) {
|
|||
return action_new_function(vhost_simple, NULL, vhost_simple_free, sd);
|
||||
}
|
||||
|
||||
static handler_t vhost_map(vrequest *vr, gpointer param, gpointer *context) {
|
||||
value *v;
|
||||
vhost_map_data *md = param;
|
||||
gboolean debug = _OPTION(vr, md->plugin, 0).boolean;
|
||||
|
||||
UNUSED(context);
|
||||
|
||||
v = g_hash_table_lookup(md->hash, vr->request.uri.host);
|
||||
|
||||
if (v) {
|
||||
if (debug)
|
||||
VR_DEBUG(vr, "vhost_map: host %s found in hashtable", vr->request.uri.host->str);
|
||||
action_enter(vr, v->data.val_action.action);
|
||||
} else if (md->default_action) {
|
||||
if (debug)
|
||||
VR_DEBUG(vr, "vhost_map: host %s not found in hashtable, executing default action", vr->request.uri.host->str);
|
||||
action_enter(vr, md->default_action->data.val_action.action);
|
||||
} else {
|
||||
if (debug)
|
||||
VR_DEBUG(vr, "vhost_map: neither host %s found in hashtable nor default action specified, doing nothing", vr->request.uri.host->str);
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
static void vhost_map_free(server *srv, gpointer param) {
|
||||
vhost_map_data *md = param;
|
||||
|
||||
UNUSED(srv);
|
||||
|
||||
g_hash_table_destroy(md->hash);
|
||||
|
||||
g_slice_free(vhost_map_data, md);
|
||||
}
|
||||
|
||||
static action* vhost_map_create(server *srv, plugin* p, value *val) {
|
||||
GHashTableIter iter;
|
||||
gpointer k, v;
|
||||
vhost_map_data *md;
|
||||
GString *str;
|
||||
|
||||
if (!val || val->type != VALUE_HASH) {
|
||||
ERROR(srv, "%s", "vhost.map expects a hashtable as parameter");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
md = g_slice_new0(vhost_map_data);
|
||||
md->plugin = p;
|
||||
md->hash = value_extract(val).hash;
|
||||
str = g_string_new_len(CONST_STR_LEN("default"));
|
||||
md->default_action = g_hash_table_lookup(md->hash, str);
|
||||
g_string_free(str, TRUE);
|
||||
|
||||
/* check if every value in the hashtable is an action */
|
||||
g_hash_table_iter_init(&iter, md->hash);
|
||||
while (g_hash_table_iter_next(&iter, &k, &v)) {
|
||||
val = v;
|
||||
|
||||
if (val->type != VALUE_ACTION) {
|
||||
ERROR(srv, "vhost.map expects a hashtable with action values as parameter, %s value given", value_type_string(val->type));
|
||||
vhost_map_free(srv, md);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
action_acquire(val->data.val_action.action);
|
||||
}
|
||||
|
||||
return action_new_function(vhost_map, NULL, vhost_map_free, md);
|
||||
}
|
||||
|
||||
|
||||
static const plugin_option options[] = {
|
||||
{ "vhost.debug", VALUE_BOOLEAN, NULL, NULL, NULL },
|
||||
|
@ -178,6 +277,7 @@ static const plugin_option options[] = {
|
|||
|
||||
static const plugin_action actions[] = {
|
||||
{ "vhost.simple", vhost_simple_create },
|
||||
{ "vhost.map", vhost_map_create },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue