httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject [PATCH] vhosts revamp
Date Sun, 05 Oct 1997 09:05:44 GMT
I haven't finished testing this yet.  But it's passing some basic tests. 
I'm writing a test suite. 

The patch is huge because it moves the scattered pieces from all over the
place into http_vhost.c.  You may want to go peruse http_vhost.c and then
scream at me because of the complexity of the data structure.

I hope I'm still happy with this when I wake up tomorrow :) 

Dean

Index: Makefile.tmpl
===================================================================
RCS file: /export/home/cvs/apachen/src/main/Makefile.tmpl,v
retrieving revision 1.4
diff -u -r1.4 Makefile.tmpl
--- Makefile.tmpl	1997/09/10 20:05:37	1.4
+++ Makefile.tmpl	1997/10/05 08:54:43
@@ -11,7 +11,7 @@
 OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o \
   http_log.o http_protocol.o rfc1413.o util.o util_script.o buff.o\
   md5c.o util_md5.o explain.o http_bprintf.o util_date.o util_snprintf.o \
-  fnmatch.o
+  fnmatch.o http_vhost.o
 
 .c.o:
 	$(CC) -c $(INCLUDES) $(CFLAGS) $(SPACER) $<
@@ -46,7 +46,7 @@
 http_bprintf.o: http_bprintf.c httpd.h conf.h alloc.h buff.h
 http_config.o: http_config.c httpd.h conf.h alloc.h buff.h \
  http_config.h http_core.h http_log.h http_request.h \
- http_conf_globals.h explain.h
+ http_conf_globals.h explain.h http_vhost.h
 http_core.o: http_core.c httpd.h conf.h alloc.h buff.h http_config.h \
  http_core.h http_protocol.h http_conf_globals.h http_main.h \
  http_log.h rfc1413.h util_md5.h md5.h scoreboard.h fnmatch.h
@@ -54,10 +54,11 @@
  http_core.h http_log.h
 http_main.o: http_main.c httpd.h conf.h alloc.h buff.h http_main.h \
  http_log.h http_config.h http_protocol.h http_request.h \
- http_conf_globals.h http_core.h scoreboard.h multithread.h explain.h
+ http_conf_globals.h http_core.h scoreboard.h multithread.h explain.h \
+ http_vhost.h
 http_protocol.o: http_protocol.c httpd.h conf.h alloc.h buff.h \
  http_config.h http_core.h http_protocol.h http_main.h http_log.h \
- util_date.h
+ util_date.h http_vhost.h
 http_request.o: http_request.c httpd.h conf.h alloc.h buff.h \
  http_config.h http_request.h http_core.h http_protocol.h http_log.h \
  http_main.h scoreboard.h fnmatch.h
Index: http_conf_globals.h
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_conf_globals.h,v
retrieving revision 1.17
diff -u -r1.17 http_conf_globals.h
--- http_conf_globals.h	1997/08/05 06:02:40	1.17
+++ http_conf_globals.h	1997/10/05 08:54:43
@@ -87,8 +87,6 @@
 extern char server_root[MAX_STRING_LEN];
 extern char server_confname[MAX_STRING_LEN];
 
-extern server_rec_chain *vhash_table[VHASH_TABLE_SIZE + VHASH_EXTRA_SLOP];
-
 /* We want this to have the least chance of being correupted if there
  * is some memory corruption, so we allocate it statically.
  */
Index: http_config.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_config.c,v
retrieving revision 1.80
diff -u -r1.80 http_config.c
--- http_config.c	1997/09/16 00:17:59	1.80
+++ http_config.c	1997/10/05 08:54:43
@@ -73,6 +73,7 @@
 #include "http_log.h"		/* for errors in parse_htaccess */
 #include "http_request.h"	/* for default_handler (see invoke_handler) */
 #include "http_conf_globals.h"	/* Sigh... */
+#include "http_vhost.h"
 #include "explain.h"
 
 DEF_Explain
@@ -1019,96 +1020,11 @@
     return OK;
 }
 
-/*****************************************************************
- *
- * Virtual host stuff; note that the commands that invoke this stuff
- * are with the command table in http_core.c.
- */
-
-/*
- * Parses a host of the form <address>[:port]
- * paddr is used to create a list in the order of input
- * **paddr is the ->next pointer of the last entry (or s->addrs)
- * *paddr is the variable used to keep track of **paddr between calls
- * port is the default port to assume
- */
-static void get_addresses(pool *p, char *w, server_addr_rec ***paddr, unsigned port)
-{
-    struct hostent *hep;
-    unsigned long my_addr;
-    server_addr_rec *sar;
-    char *t;
-    int i, is_an_ip_addr;
-
-    if (*w == 0)
-	return;
-
-    t = strchr(w, ':');
-    if (t) {
-	if (strcmp(t + 1, "*") == 0) {
-	    port = 0;
-	}
-	else if ((i = atoi(t + 1))) {
-	    port = i;
-	}
-	else {
-	    fprintf(stderr, "Port must be numeric\n");
-	}
-	*t = 0;
-    }
-
-    is_an_ip_addr = 0;
-    if (strcmp(w, "*") == 0) {
-	my_addr = htonl(INADDR_ANY);
-	is_an_ip_addr = 1;
-    }
-    else if (strcmp(w, "_default_") == 0
-	     || strcmp(w, "255.255.255.255") == 0) {
-	my_addr = DEFAULT_VHOST_ADDR;
-	is_an_ip_addr = 1;
-    }
-    else if ((my_addr = ap_inet_addr(w)) != INADDR_NONE) {
-	is_an_ip_addr = 1;
-    }
-    if (is_an_ip_addr) {
-	sar = pcalloc(p, sizeof(server_addr_rec));
-	**paddr = sar;
-	*paddr = &sar->next;
-	sar->host_addr.s_addr = my_addr;
-	sar->host_port = port;
-	sar->virthost = pstrdup(p, w);
-	if (t != NULL)
-	    *t = ':';
-	return;
-    }
-
-    hep = gethostbyname(w);
-
-    if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
-	fprintf(stderr, "Cannot resolve host name %s --- ignoring!\n", w);
-	if (t != NULL)
-	    *t = ':';
-	return;
-    }
-
-    for (i = 0; hep->h_addr_list[i]; ++i) {
-	sar = pcalloc(p, sizeof(server_addr_rec));
-	**paddr = sar;
-	*paddr = &sar->next;
-	sar->host_addr = *(struct in_addr *) hep->h_addr_list[i];
-	sar->host_port = port;
-	sar->virthost = pstrdup(p, w);
-    }
-
-    if (t != NULL)
-	*t = ':';
-}
 
 server_rec *init_virtual_host(pool *p, const char *hostname,
 			      server_rec *main_server)
 {
     server_rec *s = (server_rec *) pcalloc(p, sizeof(server_rec));
-    server_addr_rec **addrs;
 
 #ifdef RLIMIT_NOFILE
     struct rlimit limits;
@@ -1134,24 +1050,8 @@
     s->keep_alive_max = -1;
     s->error_log = main_server->error_log;
     s->loglevel = main_server->loglevel;
-
-    /* start the list of addreses */
-    addrs = &s->addrs;
-    while (hostname[0]) {
-	get_addresses(p, getword_conf(p, &hostname), &addrs,
-		      main_server->port);
-    }
-    /* terminate the list */
-    *addrs = NULL;
-    if (s->addrs) {
-	if (s->addrs->host_port) {
-	    s->port = s->addrs->host_port;	/* set them the same, by default */
-	}
-	else {
-	    /* otherwise we get a port of 0 on redirects */
-	    s->port = main_server->port;
-	}
-    }
+    /* useful default, otherwise we get a port of 0 on redirects */
+    s->port = main_server->port;
     s->next = NULL;
 
     s->is_virtual = 1;
@@ -1163,13 +1063,11 @@
     s->server_uid = user_id;
     s->server_gid = group_id;
 
+    parse_vhost_addrs(p, hostname, s);
+
     return s;
 }
 
-int is_virtual_server(server_rec *s)
-{
-    return s->is_virtual;
-}
 
 void fixup_virtual_hosts(pool *p, server_rec *main_server)
 {
@@ -1240,8 +1138,7 @@
     listenbacklog = DEFAULT_LISTENBACKLOG;
 
     /* Global virtual host hash bucket pointers.  Init to null. */
-    memset(vhash_table, 0,
-	   (VHASH_TABLE_SIZE + VHASH_EXTRA_SLOP) * sizeof(vhash_table[0]));
+    init_vhost_config(p);
 
     strncpy(coredump_dir, server_root, sizeof(coredump_dir) - 1);
     coredump_dir[sizeof(coredump_dir) - 1] = '\0';
@@ -1309,6 +1206,7 @@
 
     fixup_virtual_hosts(p, s);
     default_listeners(p, s);
+    fini_vhost_config(p, s);
 
     return s;
 }
Index: http_config.h
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_config.h,v
retrieving revision 1.51
diff -u -r1.51 http_config.h
--- http_config.h	1997/09/16 00:18:03	1.51
+++ http_config.h	1997/10/05 08:54:44
@@ -297,6 +297,7 @@
 void *create_request_config(pool *p);
 void *create_per_dir_config(pool *p);
 void *merge_per_dir_configs(pool *p, void *base, void *new);
+void *create_empty_config(pool *p);
 
 void core_reorder_directories(pool *, server_rec *);
 
@@ -307,7 +308,6 @@
 const char *srm_command_loop(cmd_parms *parms, void *config);
 
 server_rec *init_virtual_host(pool *p, const char *hostname, server_rec *main_server);
-int is_virtual_server(server_rec *);
 void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp);
 
 /* Module-method dispatchers, also for http_request.c */
Index: http_core.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_core.c,v
retrieving revision 1.123
diff -u -r1.123 http_core.c
--- http_core.c	1997/09/25 01:03:21	1.123
+++ http_core.c	1997/10/05 08:54:44
@@ -57,7 +57,7 @@
 #include "http_protocol.h"	/* For index_of_response().  Grump. */
 #include "http_request.h"
 #include "http_conf_globals.h"
-
+#include "http_vhost.h"
 #include "http_main.h"		/* For the default_handler below... */
 #include "http_log.h"
 #include "rfc1413.h"
@@ -1554,6 +1554,8 @@
 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1, "The location of the directory Apache changes to before dumping core" },
 { "Include", include_config, NULL, RSRC_CONF, TAKE1, "config file to be included" },
 { "LogLevel", set_loglevel, NULL, RSRC_CONF, TAKE1, "set level of verbosity in error logging" },
+{ "NameVirtualHost", set_name_virtual_host, NULL, RSRC_CONF, TAKE1,
+  "a numeric ip address:port, or the name of a host with a single address" },
 { NULL },
 };
 
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.230
diff -u -r1.230 http_main.c
--- http_main.c	1997/10/05 02:06:37	1.230
+++ http_main.c	1997/10/05 08:54:45
@@ -83,6 +83,7 @@
 #include "http_request.h"	/* for process_request */
 #include "http_conf_globals.h"
 #include "http_core.h"		/* for get_remote_host */
+#include "http_vhost.h"
 #include "scoreboard.h"
 #include "multithread.h"
 #include <sys/stat.h>
@@ -195,23 +196,6 @@
 listen_rec *listeners;
 static listen_rec *head_listener;
 
-/* A (n) bucket hash table, each entry has a pointer to a server rec and
- * a pointer to the other entries in that bucket.  Each individual address,
- * even for virtualhosts with multiple addresses, has an entry in this hash
- * table.  There are extra buckets for _default_, and name-vhost entries.
- *
- * The main_server's addresses appear in the main part of this table.
- * They're differentiated from real vhosts by server->is_virtual == 0.
- *
- * The VHASH_DEFAULT_BUCKET is a list of all the _default_ server_addr_recs.
- *
- * The VHASH_MAIN_BUCKET is a list of one server_addr_rec from each name
- * based vhost.  At the moment none of the name based vhost code is hashed,
- * and it's just more convenient to have a list of all the name-based vhosts
- * rather than a list of all the names of name-based vhosts.
- */
-server_rec_chain *vhash_table[VHASH_TABLE_SIZE + VHASH_EXTRA_SLOP];
-
 char server_root[MAX_STRING_LEN];
 char server_confname[MAX_STRING_LEN];
 char coredump_dir[MAX_STRING_LEN];
@@ -2222,243 +2206,7 @@
  * Connection structures and accounting...
  */
 
-/* This hashing function is designed to get good distribution in the cases
- * where the server is handling entire "networks" of servers.  i.e. a
- * whack of /24s.  This is probably the most common configuration for
- * ISPs with large virtual servers.
- *
- * Hash function provided by David Hankins.
- */
-static ap_inline unsigned hash_inaddr(unsigned key)
-{
-    key ^= (key >> 16);
-    return ((key >> 8) ^ key) % VHASH_TABLE_SIZE;
-}
-
-static server_rec *find_virtual_server(struct in_addr server_ip,
-				       unsigned port, server_rec *server)
-{
-    server_addr_rec *sar;
-    server_rec_chain *trav;
-    unsigned buk;
-
-    /* scan the hash table for an exact match first */
-    buk = hash_inaddr(server_ip.s_addr);
-    for (trav = vhash_table[buk]; trav; trav = trav->next) {
-	sar = trav->sar;
-	if ((sar->host_addr.s_addr == server_ip.s_addr)
-	    && (sar->host_port == 0 || sar->host_port == port)) {
-	    if (trav->server->is_virtual) {
-		return trav->server;
-	    }
-	    /* otherwise it's the "main server address", and we need
-	     * to do _default_ handling
-	     */
-	    break;
-	}
-    }
-
-    /* return the main server for now, might switch to a _default_ later */
-    return server_conf;
-}
-
-
-static void add_to_vhash_bucket(unsigned buk, server_rec *s,
-				server_addr_rec *sar)
-{
-    server_rec_chain *hashme;
-
-    hashme = palloc(pconf, sizeof(*hashme));
-    hashme->server = s;
-    hashme->sar = sar;
-    hashme->next = vhash_table[buk];
-    vhash_table[buk] = hashme;
-}
-
-
-/* hash table statistics, keep this in here for the beta period so
- * we can find out if the hash function is ok
- */
-#define VHASH_STATISTICS
-#ifdef VHASH_STATISTICS
-static int vhash_compare(const void *a, const void *b)
-{
-    return (*(const int *) b - *(const int *) a);
-}
 
-static void dump_vhash_statistics(void)
-{
-    unsigned count[VHASH_TABLE_SIZE + VHASH_EXTRA_SLOP];
-    int i;
-    server_rec_chain *src;
-    unsigned total;
-    char buf[HUGE_STRING_LEN];
-    char *p;
-
-    total = 0;
-    for (i = 0; i < VHASH_TABLE_SIZE + VHASH_EXTRA_SLOP; ++i) {
-	count[i] = 0;
-	for (src = vhash_table[i]; src; src = src->next) {
-	    ++count[i];
-	    if (i < VHASH_TABLE_SIZE) {
-		/* don't count the slop buckets in the total */
-		++total;
-	    }
-	}
-    }
-    qsort(count, VHASH_TABLE_SIZE, sizeof(count[0]), vhash_compare);
-    p = buf + ap_snprintf(buf, sizeof(buf),
-		 "vhash: total hashed = %u, avg chain = %u, #default = %u, "
-			  "#name-vhost = %u, chain lengths (count x len):",
-	       total, total / VHASH_TABLE_SIZE, count[VHASH_DEFAULT_BUCKET],
-			  count[VHASH_MAIN_BUCKET]);
-    total = 1;
-    for (i = 1; i < VHASH_TABLE_SIZE; ++i) {
-	if (count[i - 1] != count[i]) {
-	    p += ap_snprintf(p, sizeof(buf) - (p - buf), " %ux%u",
-			     total, count[i - 1]);
-	    total = 1;
-	}
-	else {
-	    ++total;
-	}
-    }
-    p += ap_snprintf(p, sizeof(buf) - (p - buf), " %ux%u",
-		     total, count[VHASH_TABLE_SIZE - 1]);
-    aplog_error(APLOG_MARK, APLOG_DEBUG, server_conf, buf);
-}
-#endif
-
-
-void default_server_hostnames(server_rec *main_s)
-{
-    struct hostent *h;
-    char *def_hostname;
-    int n;
-    server_addr_rec *sar;
-    server_addr_rec *main_sar;
-    int has_default_vhost_addr;
-    int from_local = 0;
-    server_rec *s;
-    int is_namevhost;
-
-    /* Main host first */
-    s = main_s;
-
-    if (!s->server_hostname) {
-	s->server_hostname = get_local_host(pconf);
-	from_local = 1;
-    }
-
-    def_hostname = s->server_hostname;
-    h = gethostbyname(def_hostname);
-    if (h == NULL) {
-	fprintf(stderr, "httpd: cannot determine the IP address of ");
-	if (from_local) {
-	    fprintf(stderr, "the local host (%s). Use ServerName to set it manually.\n",
-		    s->server_hostname ? s->server_hostname : "<NULL>");
-	}
-	else {
-	    fprintf(stderr, "the specified ServerName (%s).\n",
-		    s->server_hostname ? s->server_hostname : "<NULL>");
-	};
-	exit(1);
-    }
-
-    /* we fill in s->addrs for two reasons.  One so that we have
-     * server_addr_recs for the hash table.  And also because gethostbyname
-     * and gethostbyaddr share a static data area and our result would be
-     * clobbered here if we didn't copy it somewhere. -djg
-     */
-    for (n = 0; h->h_addr_list[n] != NULL; n++) {
-	main_sar = pcalloc(pconf, sizeof(*main_sar));
-	main_sar->host_addr = *(struct in_addr *) h->h_addr_list[n];
-	main_sar->host_port = 0;	/* we want this to match all ports */
-	main_sar->virthost = s->server_hostname;
-	main_sar->next = s->addrs;
-	s->addrs = main_sar;
-	add_to_vhash_bucket(hash_inaddr(main_sar->host_addr.s_addr),
-			    s, main_sar);
-    }
-
-    /* Then virtual hosts */
-
-    for (s = s->next; s; s = s->next) {
-	/* Check to see if we might be a HTTP/1.1 virtual host - same IP */
-	has_default_vhost_addr = 0;
-	for (sar = s->addrs; sar; sar = sar->next) {
-	    is_namevhost = 0;	/* guess addr doesn't match main server */
-	    for (main_sar = main_s->addrs; main_sar; main_sar = main_sar->next) {
-		if (sar->host_addr.s_addr == main_sar->host_addr.s_addr
-		    && s->port == main_s->port) {
-		    add_to_vhash_bucket(VHASH_MAIN_BUCKET, s, sar);
-		    /* XXX: only add it to the main bucket once since we're
-		     * not optimizing name-vhosts yet */
-		    s->is_virtual = 2;
-		    is_namevhost = 1;
-		    break;
-		}
-	    }
-	    if (sar->host_addr.s_addr == DEFAULT_VHOST_ADDR
-		|| sar->host_addr.s_addr == INADDR_ANY) {
-		/* XXX: this probably isn't the best handling of INADDR_ANY */
-		/* add it to default bucket for each appropriate sar
-		 * since we need to do a port test
-		 */
-		has_default_vhost_addr = 1;
-		add_to_vhash_bucket(VHASH_DEFAULT_BUCKET, s, sar);
-	    }
-	    else if (!is_namevhost) {
-		add_to_vhash_bucket(hash_inaddr(sar->host_addr.s_addr),
-				    s, sar);
-	    }
-	}
-
-	/* FIXME: some of this decision doesn't make a lot of sense in
-	   the presence of multiple addresses on the <VirtualHost>
-	   directive.  It should issue warnings here perhaps. -djg */
-	if (!s->server_hostname) {
-	    if (s->is_virtual == 2) {
-		if (s->addrs) {
-		    s->server_hostname = s->addrs->virthost;
-		}
-		else {
-		    /* what else can we do?  at this point this vhost has
-		       no configured name, probably because they used
-		       DNS in the VirtualHost statement.  It's disabled
-		       anyhow by the host matching code.  -djg */
-		    s->server_hostname =
-			pstrdup(pconf, "bogus_host_without_forward_dns");
-		}
-	    }
-	    else if (has_default_vhost_addr) {
-		s->server_hostname = def_hostname;
-	    }
-	    else {
-		if (s->addrs
-		    && (h = gethostbyaddr((char *) &(s->addrs->host_addr),
-					sizeof(struct in_addr), AF_INET))) {
-		    s->server_hostname = pstrdup(pconf, (char *) h->h_name);
-		}
-		else {
-		    /* again, what can we do?  They didn't specify a
-		       ServerName, and their DNS isn't working. -djg */
-		    if (s->addrs) {
-			fprintf(stderr, "Failed to resolve server name "
-				"for %s (check DNS)\n",
-				inet_ntoa(s->addrs->host_addr));
-		    }
-		    s->server_hostname =
-			pstrdup(pconf, "bogus_host_without_reverse_dns");
-		}
-	    }
-	}
-    }
-
-#ifdef VHASH_STATISTICS
-    dump_vhash_statistics();
-#endif
-}
 
 conn_rec *new_connection(pool *p, server_rec *server, BUFF *inout,
 			 const struct sockaddr_in *remaddr,
@@ -2475,8 +2223,8 @@
 
     conn->pool = p;
     conn->local_addr = *saddr;
-    conn->server = find_virtual_server(saddr->sin_addr, ntohs(saddr->sin_port),
-				       server);
+    conn->server = server; /* just a guess for now */
+    update_vhost_given_ip(conn);
     conn->base_server = conn->server;
     conn->client = inout;
 
@@ -3393,7 +3141,6 @@
 	    note_cleanups_for_fd(pconf, scoreboard_fd);
 	}
 #endif
-	default_server_hostnames(server_conf);
 
 	set_signals();
 	log_pid(pconf, pid_fname);
@@ -3656,7 +3403,6 @@
 	open_logs(server_conf, pconf);
 	init_modules(pconf, server_conf);
 	set_group_privs();
-	default_server_hostnames(server_conf);
 
 #ifdef MPE
 	/* Only try to switch if we're running as MANAGER.SYS */
@@ -4085,7 +3831,6 @@
     restart_time = time(NULL);
 
     reinit_scoreboard(pconf);
-    default_server_hostnames(server_conf);
 
     acquire_mutex(start_mutex);
 
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_protocol.c,v
retrieving revision 1.163
diff -u -r1.163 http_protocol.c
--- http_protocol.c	1997/09/26 03:26:24	1.163
+++ http_protocol.c	1997/10/05 08:54:45
@@ -64,6 +64,7 @@
 #include "http_protocol.h"
 #include "http_main.h"
 #include "http_request.h"
+#include "http_vhost.h"
 #include "http_log.h"           /* For errors detected in basic auth common
                                  * support code... */
 #include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
@@ -757,114 +758,6 @@
     }
 }
 
-static void check_hostalias(request_rec *r)
-{
-    const char *hostname = r->hostname;
-    char *host = getword(r->pool, &hostname, ':');      /* Get rid of port */
-    unsigned port = (*hostname) ? atoi(hostname) : 80;
-    server_rec *s;
-    int l;
-    server_rec_chain *src;
-
-    if (port && (port != r->server->port))
-        return;
-
-    l = strlen(host) - 1;
-    if ((host[l]) == '.') {
-        host[l] = '\0';
-    }
-
-    r->hostname = host;
-
-    for (src = vhash_table[VHASH_MAIN_BUCKET]; src; src = src->next) {
-        const char *names;
-        server_addr_rec *sar;
-
-        s = src->server;
-
-        /* s->addrs != NULL because it's in a hash bucket.
-         *
-         * Note that default_server_hostnames has ensured that each
-         * name-vhost appears only once in the VHASH_MAIN_BUCKET.
-         */
-
-        if ((!strcasecmp(host, s->server_hostname)) && (port == s->port)) {
-            r->server = r->connection->server = s;
-            if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
-                r->uri += r->hostlen;
-                parse_uri(r, r->uri);
-            }
-        }
-
-        /* search all the names from <VirtualHost> directive */
-        for (sar = s->addrs; sar; sar = sar->next) {
-            if (!strcasecmp(sar->virthost, host) &&
-                ((sar->host_port == 0) || (port == sar->host_port))) {
-                r->server = r->connection->server = s;
-                if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
-                    r->uri += r->hostlen;
-                    r->proxyreq = 0;
-                }
-            }
-        }
-
-        /* search all the aliases from ServerAlias directive */
-        names = s->names;
-        if (names) {
-            while (*names) {
-                char *name = getword_conf(r->pool, &names);
-
-                if ((is_matchexp(name) && !strcasecmp_match(host, name)) ||
-                    (!strcasecmp(host, name))) {
-                    r->server = r->connection->server = s;
-                    if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
-                        r->uri += r->hostlen;
-                        r->proxyreq = 0;
-                    }
-                }
-            }
-        }
-    }
-}
-
-void check_serverpath(request_rec *r)
-{
-    server_rec *s;
-    server_rec_chain *src;
-
-    /*
-     * This is in conjunction with the ServerPath code in http_core, so we
-     * get the right host attached to a non- Host-sending request.
-     */
-
-    for (src = vhash_table[VHASH_MAIN_BUCKET]; src; src = src->next) {
-        s = src->server;
-        if (s->addrs && s->path && !strncmp(r->uri, s->path, s->pathlen) &&
-            (s->path[s->pathlen - 1] == '/' ||
-             r->uri[s->pathlen] == '/' ||
-             r->uri[s->pathlen] == '\0'))
-            r->server = r->connection->server = s;
-    }
-}
-
-
-static void check_default_server(request_rec *r)
-{
-    server_addr_rec *sar;
-    server_rec_chain *trav;
-    unsigned port;
-
-    port = ntohs(r->connection->local_addr.sin_port);
-    for (trav = vhash_table[VHASH_DEFAULT_BUCKET]; trav; trav = trav->next) {
-        sar = trav->sar;
-        if (sar->host_port == 0 || sar->host_port == port) {
-            /* match! */
-            r->server = r->connection->server = trav->server;
-            return;
-        }
-    }
-}
-
 request_rec *read_request(conn_rec *conn)
 {
     request_rec *r = (request_rec *) pcalloc(conn->pool, sizeof(request_rec));
@@ -912,26 +805,10 @@
 
     r->status = HTTP_OK;                         /* Until further notice. */
 
-    /* if it's the main server so far, we have to do name-vhost style lookups */
-
-    if (r->server->is_virtual == 0) {
-        if (r->hostname || (r->hostname = table_get(r->headers_in, "Host")))
-            check_hostalias(r);
-        else
-            check_serverpath(r);
-        /* if that failed, then look for a default server */
-        if (r->server->is_virtual == 0) {
-            check_default_server(r);
-        }
-    }
-    else if (!r->hostname) {
-        /* must set this for HTTP/1.1 support */
-        r->hostname = table_get(r->headers_in, "Host");
-    }
-    /* we have finished the search for a vhost */
-
-    /* we may have switched to another server */
-    r->per_dir_config = r->server->lookup_defaults;
+    /* update what we think the virtual host is based on the headers we've
+     * now read
+     */
+    update_vhost_from_headers(r);
 
     conn->keptalive = 0;        /* We now have a request to play with */
 
Index: http_vhost.c
===================================================================
RCS file: http_vhost.c
diff -N http_vhost.c
--- /dev/null	Sun Oct  5 01:54:00 1997
+++ http_vhost.c	Sun Oct  5 01:54:46 1997
@@ -0,0 +1,707 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 The Apache Group.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+/*
+ * http_vhost.c: functions pertaining to virtual host addresses
+ *	(configuration and run-time)
+ */
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_conf_globals.h"
+#include "http_log.h"
+#include "http_vhost.h"
+#include "http_protocol.h"
+
+/*
+ * After all the definitions there's an explanation of how it's all put
+ * together.
+ */
+
+/* meta-list of name-vhosts.  Each server_rec can be in possibly multiple
+ * lists of name-vhosts.
+ */
+typedef struct name_chain name_chain;
+struct name_chain {
+    name_chain *next;
+    server_addr_rec *sar;	/* the record causing it to be in
+				 * this chain (needed for port comparisons) */
+    server_rec *server;		/* the server to use on a match */
+};
+
+/* meta-list of ip addresses.  Each server_rec can be in possibly multiple
+ * hash chains since it can have multiple ips.
+ */
+typedef struct ipaddr_chain ipaddr_chain;
+struct ipaddr_chain {
+    ipaddr_chain *next;
+    server_addr_rec *sar;	/* the record causing it to be in
+				 * this chain (need for both ip addr and port
+				 * comparisons) */
+    server_rec *server;		/* the server to use if this matches */
+    name_chain *names;		/* if non-NULL then a list of name-vhosts
+    				 * sharing this address */
+};
+
+/* This defines the size of the hash table used for hashing ip addresses
+ * of virtual hosts.  It must be a power of two.
+ */
+#ifndef IPHASH_TABLE_SIZE
+#define IPHASH_TABLE_SIZE 256
+#endif
+
+/* A (n) bucket hash table, each entry has a pointer to a server rec and
+ * a pointer to the other entries in that bucket.  Each individual address,
+ * even for virtualhosts with multiple addresses, has an entry in this hash
+ * table.  There are extra buckets for _default_, and name-vhost entries.
+ *
+ * Note that after config time this is constant, so it is thread-safe.
+ */
+static ipaddr_chain *iphash_table[IPHASH_TABLE_SIZE];
+
+/* dump out statistics about the hash function */
+#define IPHASH_STATISTICS
+
+/* list of the _default_ servers */
+static ipaddr_chain *default_list;
+
+/* list of the NameVirtualHost addresses */
+static server_addr_rec *name_vhost_list;
+static server_addr_rec **name_vhost_list_tail;
+
+
+/*
+ * How it's used:
+ *
+ * The ip address determines which chain in iphash_table is interesting, then
+ * a comparison is done down that chain to find the first ipaddr_chain whose
+ * sar matches the address:port pair.
+ *
+ * If that ipaddr_chain has names == NULL then you're done, it's an ip-vhost.
+ *
+ * Otherwise it's a name-vhost list, and the default is the server in the
+ * ipaddr_chain record.  We tuck away the ipaddr_chain record in the
+ * conn_rec field vhost_lookup_data.  Later on after the headers we get a
+ * second chance, and we use the name_chain to figure out what name-vhost
+ * matches the headers.
+ *
+ * If there was no ip address match in the iphash_table then do a lookup
+ * in the default_list.
+ *
+ * How it's put together ... well you should be able to figure that out
+ * from how it's used.  Or something like that.
+ */
+
+
+/* called at the beginning of the config */
+void init_vhost_config(pool *p)
+{
+    memset(iphash_table, 0, sizeof(iphash_table));
+    default_list = NULL;
+    name_vhost_list = NULL;
+    name_vhost_list_tail = &name_vhost_list;
+}
+
+
+/*
+ * Parses a host of the form <address>[:port]
+ * paddr is used to create a list in the order of input
+ * **paddr is the ->next pointer of the last entry (or s->addrs)
+ * *paddr is the variable used to keep track of **paddr between calls
+ * port is the default port to assume
+ */
+static void get_addresses(pool *p, char *w, server_addr_rec ***paddr,
+			    unsigned port)
+{
+    struct hostent *hep;
+    unsigned long my_addr;
+    server_addr_rec *sar;
+    char *t;
+    int i, is_an_ip_addr;
+
+    if (*w == 0)
+	return;
+
+    t = strchr(w, ':');
+    if (t) {
+	if (strcmp(t + 1, "*") == 0) {
+	    port = 0;
+	}
+	else if ((i = atoi(t + 1))) {
+	    port = i;
+	}
+	else {
+	    fprintf(stderr, "Port must be numeric\n");
+	}
+	*t = 0;
+    }
+
+    is_an_ip_addr = 0;
+    if (strcmp(w, "*") == 0) {
+	my_addr = htonl(INADDR_ANY);
+	is_an_ip_addr = 1;
+    }
+    else if (strcmp(w, "_default_") == 0
+	     || strcmp(w, "255.255.255.255") == 0) {
+	my_addr = DEFAULT_VHOST_ADDR;
+	is_an_ip_addr = 1;
+    }
+    else if ((my_addr = ap_inet_addr(w)) != INADDR_NONE) {
+	is_an_ip_addr = 1;
+    }
+    if (is_an_ip_addr) {
+	sar = pcalloc(p, sizeof(server_addr_rec));
+	**paddr = sar;
+	*paddr = &sar->next;
+	sar->host_addr.s_addr = my_addr;
+	sar->host_port = port;
+	sar->virthost = pstrdup(p, w);
+	if (t != NULL)
+	    *t = ':';
+	return;
+    }
+
+    hep = gethostbyname(w);
+
+    if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
+	fprintf(stderr, "Cannot resolve host name %s --- ignoring!\n", w);
+	if (t != NULL)
+	    *t = ':';
+	return;
+    }
+
+    for (i = 0; hep->h_addr_list[i]; ++i) {
+	sar = pcalloc(p, sizeof(server_addr_rec));
+	**paddr = sar;
+	*paddr = &sar->next;
+	sar->host_addr = *(struct in_addr *) hep->h_addr_list[i];
+	sar->host_port = port;
+	sar->virthost = pstrdup(p, w);
+    }
+
+    if (t != NULL)
+	*t = ':';
+}
+
+
+/* parse the <VirtualHost> addresses */
+void parse_vhost_addrs(pool *p, const char *hostname, server_rec *s)
+{
+    server_addr_rec **addrs;
+
+    /* start the list of addreses */
+    addrs = &s->addrs;
+    while (hostname[0]) {
+	get_addresses(p, getword_conf(p, &hostname), &addrs, s->port);
+    }
+    /* terminate the list */
+    *addrs = NULL;
+    if (s->addrs) {
+	if (s->addrs->host_port) {
+	    /* override the default port which is inherited from main_server */
+	    s->port = s->addrs->host_port;
+	}
+    }
+}
+
+
+const char *set_name_virtual_host (cmd_parms *cmd, void *dummy, char *arg)
+{
+    /* XXX: should probably be main_server->port ... but that's inaccessible */
+    get_addresses(cmd->pool, arg, &name_vhost_list_tail, DEFAULT_PORT);
+    return NULL;
+}
+
+
+/* hash table statistics, keep this in here for the beta period so
+ * we can find out if the hash function is ok
+ */
+#ifdef IPHASH_STATISTICS
+static int iphash_compare(const void *a, const void *b)
+{
+    return (*(const int *) b - *(const int *) a);
+}
+
+
+static void dump_iphash_statistics(server_rec *main_s)
+{
+    unsigned count[IPHASH_TABLE_SIZE];
+    int i;
+    ipaddr_chain *src;
+    unsigned total;
+    char buf[HUGE_STRING_LEN];
+    char *p;
+
+    total = 0;
+    for (i = 0; i < IPHASH_TABLE_SIZE; ++i) {
+	count[i] = 0;
+	for (src = iphash_table[i]; src; src = src->next) {
+	    ++count[i];
+	    if (i < IPHASH_TABLE_SIZE) {
+		/* don't count the slop buckets in the total */
+		++total;
+	    }
+	}
+    }
+    qsort(count, IPHASH_TABLE_SIZE, sizeof(count[0]), iphash_compare);
+    p = buf + ap_snprintf(buf, sizeof(buf),
+		    "iphash: total hashed = %u, avg chain = %u, "
+		    "chain lengths (count x len):",
+		    total, total / IPHASH_TABLE_SIZE);
+    total = 1;
+    for (i = 1; i < IPHASH_TABLE_SIZE; ++i) {
+	if (count[i - 1] != count[i]) {
+	    p += ap_snprintf(p, sizeof(buf) - (p - buf), " %ux%u",
+			     total, count[i - 1]);
+	    total = 1;
+	}
+	else {
+	    ++total;
+	}
+    }
+    p += ap_snprintf(p, sizeof(buf) - (p - buf), " %ux%u",
+		     total, count[IPHASH_TABLE_SIZE - 1]);
+    aplog_error(APLOG_MARK, APLOG_DEBUG, main_s, buf);
+}
+#endif
+
+
+/* This hashing function is designed to get good distribution in the cases
+ * where the server is handling entire "networks" of servers.  i.e. a
+ * whack of /24s.  This is probably the most common configuration for
+ * ISPs with large virtual servers.
+ *
+ * Hash function provided by David Hankins.
+ */
+static ap_inline unsigned hash_inaddr(unsigned key)
+{
+    key ^= (key >> 16);
+    return ((key >> 8) ^ key) % IPHASH_TABLE_SIZE;
+}
+
+
+
+static ipaddr_chain *new_ipaddr_chain(pool *p,
+				    server_rec *s, server_addr_rec *sar)
+{
+    ipaddr_chain *new;
+
+    new = palloc(p, sizeof(*new));
+    new->names = NULL;
+    new->server = s;
+    new->sar = sar;
+    new->next = NULL;
+    return new;
+}
+
+
+static name_chain *new_name_chain(pool *p, server_rec *s, server_addr_rec *sar)
+{
+    name_chain *new;
+
+    new = palloc(p, sizeof(*new));
+    new->server = s;
+    new->sar = sar;
+    new->next = NULL;
+    return new;
+}
+
+
+static ap_inline ipaddr_chain *find_ipaddr(struct in_addr server_ip,
+    unsigned port)
+{
+    unsigned bucket;
+    ipaddr_chain *trav;
+
+    /* scan the hash table for an exact match first */
+    bucket = hash_inaddr(server_ip.s_addr);
+    for (trav = iphash_table[bucket]; trav; trav = trav->next) {
+	server_addr_rec *sar = trav->sar;
+	if ((sar->host_addr.s_addr == server_ip.s_addr)
+	    && (sar->host_port == 0 || sar->host_port == port)) {
+	    return trav;
+	}
+    }
+    return NULL;
+}
+
+
+/* compile the tables and such we need to do the run-time vhost lookups */
+void fini_vhost_config(pool *p, server_rec *main_s)
+{
+    server_addr_rec *sar;
+    int has_default_vhost_addr;
+    server_rec *s;
+    int i;
+    ipaddr_chain **iphash_table_tail[IPHASH_TABLE_SIZE];
+
+    /* terminate the name_vhost list */
+    *name_vhost_list_tail = NULL;
+
+    /* Main host first */
+    s = main_s;
+
+    if (!s->server_hostname) {
+	s->server_hostname = get_local_host(p);
+    }
+
+    /* initialize the tails */
+    for (i = 0; i < IPHASH_TABLE_SIZE; ++i) {
+	iphash_table_tail[i] = &iphash_table[i];
+    }
+
+    /* The first things to go into the hash table are the NameVirtualHosts
+     * Since name_vhost_list is in the same order that the directives
+     * occured in the config file, we'll copy it in that order.
+     */
+    for (sar = name_vhost_list; sar; sar = sar->next) {
+	unsigned bucket = hash_inaddr(sar->host_addr.s_addr);
+	ipaddr_chain *new = new_ipaddr_chain(p, NULL, sar);
+
+	*iphash_table_tail[bucket] = new;
+	iphash_table_tail[bucket] = &new->next;
+
+	/* Notice that what we've done is insert an ipaddr_chain with
+	 * both server and names NULL.  Remember that.
+	 */
+    }
+
+    /* The next things to go into the hash table are the virtual hosts
+     * themselves.  They're listed off of main_s->next in the reverse
+     * order they occured in the config file, so we insert them at
+     * the iphash_table_tail but don't advance the tail.
+     */
+
+    for (s = main_s->next; s; s = s->next) {
+	has_default_vhost_addr = 0;
+	for (sar = s->addrs; sar; sar = sar->next) {
+	    ipaddr_chain *ic;
+
+	    if (sar->host_addr.s_addr == DEFAULT_VHOST_ADDR
+		|| sar->host_addr.s_addr == INADDR_ANY) {
+		/* add it to default bucket for each appropriate sar
+		 * since we need to do a port test
+		 */
+		has_default_vhost_addr = 1;
+		ic = new_ipaddr_chain(p, s, sar);
+		ic->next = default_list;
+		default_list = ic;
+	    }
+	    else {
+		/* see if it matches something we've already got */
+		ic = find_ipaddr(sar->host_addr, sar->host_port);
+
+		/* the first time we encounter a NameVirtualHost address
+		 * ic->server will be NULL, on subsequent encounters
+		 * ic->names will be non-NULL.
+		 */
+		if (ic && (ic->names || ic->server == NULL)) {
+		    name_chain *nc = new_name_chain(p, s, sar);
+		    nc->next = ic->names;
+		    ic->names = nc;
+		    ic->server = s;
+		}
+		else if (ic) {
+		    fprintf(stderr, "VirtualHost %s overlaps with "
+			    "VirtualHost %s, ignoring %s\n", sar->virthost,
+			    ic->sar->virthost, ic->sar->virthost);
+		    ic->sar = sar;
+		    ic->server = s;
+		}
+		else {
+		    unsigned bucket = hash_inaddr(sar->host_addr.s_addr);
+
+		    ic = new_ipaddr_chain(p, s, sar);
+		    ic->next = *iphash_table_tail[bucket];
+		    *iphash_table_tail[bucket] = ic;
+		}
+	    }
+	}
+
+	/* Ok now we want to set up a server_hostname if the user was
+	 * silly enough to forget one.
+	 * XXX: This is silly we should just crash and burn.
+	 */
+	if (!s->server_hostname) {
+	    if (has_default_vhost_addr) {
+		s->server_hostname = main_s->server_hostname;
+	    }
+	    else if (!s->addrs) {
+		/* what else can we do?  at this point this vhost has
+		    no configured name, probably because they used
+		    DNS in the VirtualHost statement.  It's disabled
+		    anyhow by the host matching code.  -djg */
+		s->server_hostname =
+		    pstrdup(p, "bogus_host_without_forward_dns");
+	    }
+	    else {
+		struct hostent *h;
+
+		if ((h = gethostbyaddr((char *) &(s->addrs->host_addr),
+					sizeof(struct in_addr), AF_INET))) {
+		    s->server_hostname = pstrdup(p, (char *) h->h_name);
+		}
+		else {
+		    /* again, what can we do?  They didn't specify a
+		       ServerName, and their DNS isn't working. -djg */
+		    fprintf(stderr, "Failed to resolve server name "
+			    "for %s (check DNS)\n",
+			    inet_ntoa(s->addrs->host_addr));
+		    s->server_hostname =
+			pstrdup(p, "bogus_host_without_reverse_dns");
+		}
+	    }
+	}
+    }
+
+    /* now go through and delete any NameVirtualHosts that didn't have any
+     * hosts associated with them.  Lamers.
+     */
+    for (i = 0; i < IPHASH_TABLE_SIZE; ++i) {
+	ipaddr_chain **pic = &iphash_table[i];
+
+	while (*pic) {
+	    ipaddr_chain *ic = *pic;
+
+	    if (ic->server == NULL) {
+		fprintf(stderr, "NameVirtualHost %s has no VirtualHosts\n",
+			ic->sar->virthost);
+		*pic = ic->next;
+	    }
+	    else if (ic->names == NULL) {
+		/* if server != NULL and names == NULL then we're done
+		 * looking at NameVirtualHosts
+		 */
+		break;
+	    }
+	    else {
+		pic = &ic->next;
+	    }
+	}
+    }
+
+#ifdef IPHASH_STATISTICS
+    dump_iphash_statistics(main_s);
+#endif
+}
+
+
+/*****************************************************************************
+ * run-time vhost matching functions
+ */
+
+static void check_hostalias(request_rec *r)
+{
+    const char *hostname = r->hostname;
+    char *host = getword(r->pool, &hostname, ':');      /* Get rid of port */
+    unsigned port = (*hostname) ? atoi(hostname) : 80;
+    server_rec *s;
+    int l;
+    name_chain *src;
+
+    l = strlen(host) - 1;
+    if ((host[l]) == '.') {
+        host[l] = '\0';
+    }
+
+    r->hostname = host;
+
+    for (src = r->connection->vhost_lookup_data; src; src = src->next) {
+        const char *names;
+        server_addr_rec *sar;
+
+        s = src->server;
+
+        /* s->addrs != NULL because it's in a hash bucket.  */
+
+        if ((!strcasecmp(host, s->server_hostname)) && (port == s->port)) {
+            r->server = r->connection->server = s;
+            if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
+                r->uri += r->hostlen;
+                parse_uri(r, r->uri);
+            }
+	    return;
+        }
+
+        /* search all the names from <VirtualHost> directive */
+        for (sar = s->addrs; sar; sar = sar->next) {
+            if (!strcasecmp(sar->virthost, host) &&
+                ((sar->host_port == 0) || (port == sar->host_port))) {
+                r->server = r->connection->server = s;
+                if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
+                    r->uri += r->hostlen;
+                    r->proxyreq = 0;
+                }
+		return;
+            }
+        }
+
+        /* search all the aliases from ServerAlias directive */
+        names = s->names;
+        if (names) {
+            while (*names) {
+                char *name = getword_conf(r->pool, &names);
+
+                if ((is_matchexp(name) && !strcasecmp_match(host, name)) ||
+                    (!strcasecmp(host, name))) {
+                    r->server = r->connection->server = s;
+                    if (r->hostlen && !strncmp(r->uri, "http://", 7)) {
+                        r->uri += r->hostlen;
+                        r->proxyreq = 0;
+                    }
+		    return;
+                }
+            }
+        }
+    }
+}
+
+
+void check_serverpath(request_rec *r)
+{
+    server_rec *s;
+    name_chain *src;
+
+    /*
+     * This is in conjunction with the ServerPath code in http_core, so we
+     * get the right host attached to a non- Host-sending request.
+     */
+
+    for (src = r->connection->vhost_lookup_data; src; src = src->next) {
+        s = src->server;
+        if (s->addrs && s->path && !strncmp(r->uri, s->path, s->pathlen) &&
+            (s->path[s->pathlen - 1] == '/' ||
+             r->uri[s->pathlen] == '/' ||
+             r->uri[s->pathlen] == '\0')) {
+            r->server = r->connection->server = s;
+	    return;
+	}
+    }
+}
+
+
+void update_vhost_from_headers(request_rec *r)
+{
+    /* check if we tucked away a name_chain */
+    if (r->connection->vhost_lookup_data) {
+        if (r->hostname || (r->hostname = table_get(r->headers_in, "Host")))
+            check_hostalias(r);
+        else
+            check_serverpath(r);
+    }
+    else if (!r->hostname) {
+        /* must set this for HTTP/1.1 support */
+        r->hostname = table_get(r->headers_in, "Host");
+    }
+    /* we have finished the search for a vhost */
+
+    /* we may have switched to another server */
+    r->per_dir_config = r->server->lookup_defaults;
+}
+
+
+static server_rec *find_default_server(unsigned port)
+{
+    server_addr_rec *sar;
+    ipaddr_chain *trav;
+
+    for (trav = default_list; trav; trav = trav->next) {
+        sar = trav->sar;
+        if (sar->host_port == 0 || sar->host_port == port) {
+            /* match! */
+	    return trav->server;
+        }
+    }
+    return NULL;
+}
+
+
+/* Called for a new connection which has a known local_addr.  Note that the
+ * new connection is assumed to have conn->server == main server.
+ */
+void update_vhost_given_ip(conn_rec *conn)
+{
+    server_addr_rec *sar;
+    ipaddr_chain *trav;
+    unsigned bucket;
+    struct in_addr server_ip = conn->local_addr.sin_addr;
+    unsigned port = ntohs(conn->local_addr.sin_port);
+    server_rec *def;
+
+    /* scan the hash table for an exact match first */
+    bucket = hash_inaddr(server_ip.s_addr);
+    for (trav = iphash_table[bucket]; trav; trav = trav->next) {
+	sar = trav->sar;
+	if ((sar->host_addr.s_addr == server_ip.s_addr)
+	    && (sar->host_port == 0 || sar->host_port == port)) {
+
+	    /* save the name_chain for later in case this is a name-vhost */
+	    conn->vhost_lookup_data = trav->names;
+	    conn->server = trav->server;
+	    return;
+	}
+    }
+
+    /* There's certainly no name-vhosts with this address, they would have
+     * been matched above.
+     */
+    conn->vhost_lookup_data = NULL;
+
+    /* maybe there's a default server matching this port */
+    def = find_default_server(port);
+    if (def) {
+	conn->server = def;
+    }
+
+    /* otherwise we're stuck with just the main server */
+}
Index: http_vhost.h
===================================================================
RCS file: http_vhost.h
diff -N http_vhost.h
--- /dev/null	Sun Oct  5 01:54:00 1997
+++ http_vhost.h	Sun Oct  5 01:54:46 1997
@@ -0,0 +1,76 @@
+/* ====================================================================
+ * Copyright (c) 1995-1997 The Apache Group.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#ifndef HTTP_VHOST_H
+#define HTTP_VHOST_H
+
+/* called before any config is read */
+void init_vhost_config(pool *p);
+
+/* called after the config has been read */
+void fini_vhost_config(pool *p, server_rec *main_server);
+
+/* handle addresses in <VirtualHost> statement */
+void parse_vhost_addrs(pool *p, const char *hostname, server_rec *s);
+
+/* handle NameVirtualHost directive */
+const char *set_name_virtual_host (cmd_parms *cmd, void *dummy, char *arg);
+
+/* given an ip address only, give our best guess as to what vhost it is */
+void update_vhost_given_ip(conn_rec *conn);
+
+/* The above is never enough, and this is always called after the headers
+ * have been read.  It may change r->server.
+ */
+void update_vhost_from_headers(request_rec *r);
+
+#endif
Index: httpd.h
===================================================================
RCS file: /export/home/cvs/apachen/src/main/httpd.h,v
retrieving revision 1.150
diff -u -r1.150 httpd.h
--- httpd.h	1997/09/26 03:52:10	1.150
+++ httpd.h	1997/10/05 08:54:46
@@ -295,19 +295,6 @@
 #define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
 #endif
 
-/* This defines the size of the hash table used for hashing ip addresses
- * of virtual hosts.  It must be a power of two.
- */
-#ifndef VHASH_TABLE_SIZE
-#define VHASH_TABLE_SIZE 256
-#endif
-/* bucket where _default_ entries are stored */
-#define VHASH_DEFAULT_BUCKET	(VHASH_TABLE_SIZE)
-/* bucket where name-vhosts are stored */
-#define VHASH_MAIN_BUCKET	((VHASH_TABLE_SIZE)+1)
-/* number of magic buckets */
-#define VHASH_EXTRA_SLOP	2
-
 /* Number of requests to try to handle in a single process.  If <= 0,
  * the children don't die off.  That's the default here, since I'm still
  * interested in finding and stanching leaks.
@@ -645,6 +632,7 @@
     pool *pool;
     server_rec *server;
     server_rec *base_server;	/* Physical vhost this conn come in on */
+    void *vhost_lookup_data;	/* used by http_vhost.c */
 
     /* Information about the connection itself */
 
@@ -692,17 +680,6 @@
     struct in_addr host_addr;	/* The bound address, for this server */
     unsigned short host_port;	/* The bound port, for this server */
     char *virthost;		/* The name given in <VirtualHost> */
-};
-
-/* Meta linear list for hashes.  Each server_rec can be in possibly multiple
- * hash chains since it can have multiple ips
- */
-typedef struct server_rec_chain server_rec_chain;
-struct server_rec_chain {
-    server_rec_chain *next;
-    server_rec *server;
-    server_addr_rec *sar;	/* the record causing it to be in
-				 * this chain */
 };
 
 struct server_rec {




Mime
View raw message