dgaudet     97/10/07 12:34:11

  Modified:    src/main Makefile.tmpl http_conf_globals.h http_config.c
                        http_config.h http_core.c http_main.c
                        http_protocol.c httpd.h
  Added:       src/main http_vhost.c http_vhost.h
  Log:
  The final vhost revamp?  Maybe?  Who knows.  This is yet another vhost
  revamp.  This adds the NameVirtualHost directive which explicitly indicates
  which ip:port pairs are to be used for name-vhosts.  It strictly enforces
  these pools of name-vhosts, so that you can only make requests against the
  hosts in the pool associated with the ip:port connected to.  It ignores
  the port portion of the Host: header, trusting the socket port instead.
  
  All vhost matching functions have been moved into http_vhost.[ch] to make
  things a little easier to understand.
  
  Reviewed by:  Roy Fielding, Martin Kraemer
  
  Revision  Changes    Path
  1.5       +5 -4      apachen/src/main/Makefile.tmpl
  
  Index: Makefile.tmpl
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/Makefile.tmpl,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Makefile.tmpl     1997/09/10 20:05:37     1.4
  +++ Makefile.tmpl     1997/10/07 19:33:56     1.5
  @@ -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
  
  
  
  1.18      +0 -2      apachen/src/main/http_conf_globals.h
  
  Index: http_conf_globals.h
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/http_conf_globals.h,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- http_conf_globals.h       1997/08/05 06:02:40     1.17
  +++ http_conf_globals.h       1997/10/07 19:33:57     1.18
  @@ -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.
    */
  
  
  
  1.81      +10 -112   apachen/src/main/http_config.c
  
  Index: http_config.c
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/http_config.c,v
  retrieving revision 1.80
  retrieving revision 1.81
  diff -u -r1.80 -r1.81
  --- http_config.c     1997/09/16 00:17:59     1.80
  +++ http_config.c     1997/10/07 19:33:58     1.81
  @@ -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)
  +const char *init_virtual_host(pool *p, const char *hostname,
  +                           server_rec *main_server, server_rec **ps)
   {
       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,14 +1063,12 @@
       s->server_uid = user_id;
       s->server_gid = group_id;
   
  -    return s;
  -}
  +    *ps = s;
   
  -int is_virtual_server(server_rec *s)
  -{
  -    return s->is_virtual;
  +    return parse_vhost_addrs(p, hostname, s);
   }
   
  +
   void fixup_virtual_hosts(pool *p, server_rec *main_server)
   {
       server_rec *virt;
  @@ -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;
   }
  
  
  
  1.52      +3 -2      apachen/src/main/http_config.h
  
  Index: http_config.h
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/http_config.h,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -r1.51 -r1.52
  --- http_config.h     1997/09/16 00:18:03     1.51
  +++ http_config.h     1997/10/07 19:33:59     1.52
  @@ -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 *);
   
  @@ -306,8 +307,8 @@
                const char *path, const char *access_name);
   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 *);
  +const char *init_virtual_host(pool *p, const char *hostname,
  +                             server_rec *main_server, server_rec **);
   void process_resource_config(server_rec *s, char *fname, pool *p, pool 
*ptemp);
   
   /* Module-method dispatchers, also for http_request.c */
  
  
  
  1.125     +7 -2      apachen/src/main/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/http_core.c,v
  retrieving revision 1.124
  retrieving revision 1.125
  diff -u -r1.124 -r1.125
  --- http_core.c       1997/10/07 05:27:04     1.124
  +++ http_core.c       1997/10/07 19:34:00     1.125
  @@ -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"
  @@ -990,7 +990,10 @@
       if (main_server->is_virtual)
        return "<VirtualHost> doesn't nest!";
       
  -    s = init_virtual_host (p, arg, main_server);
  +    errmsg = init_virtual_host (p, arg, main_server, &s);
  +    if (errmsg)
  +     return errmsg;
  +
       s->next = main_server->next;
       main_server->next = s;
        
  @@ -1554,6 +1557,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 },
   };
   
  
  
  
  1.234     +3 -259    apachen/src/main/http_main.c
  
  Index: http_main.c
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
  retrieving revision 1.233
  retrieving revision 1.234
  diff -u -r1.233 -r1.234
  --- http_main.c       1997/10/06 15:05:32     1.233
  +++ http_main.c       1997/10/07 19:34:01     1.234
  @@ -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];
  @@ -2226,243 +2210,6 @@
    * 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_NOERRNO|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,
  @@ -2479,8 +2226,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;
   
  @@ -3397,7 +3144,6 @@
            note_cleanups_for_fd(pconf, scoreboard_fd);
        }
   #endif
  -     default_server_hostnames(server_conf);
   
        set_signals();
        log_pid(pconf, pid_fname);
  @@ -3659,7 +3405,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 */
  @@ -4088,7 +3833,6 @@
       restart_time = time(NULL);
   
       reinit_scoreboard(pconf);
  -    default_server_hostnames(server_conf);
   
       acquire_mutex(start_mutex);
   
  
  
  
  1.166     +5 -125    apachen/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/http_protocol.c,v
  retrieving revision 1.165
  retrieving revision 1.166
  diff -u -r1.165 -r1.166
  --- http_protocol.c   1997/10/07 05:27:06     1.165
  +++ http_protocol.c   1997/10/07 19:34:03     1.166
  @@ -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,23 +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 */
  +    /* update what we think the virtual host is based on the headers we've
  +     * now read
  +     */
  +    update_vhost_from_headers(r);
   
       /* we may have switched to another server */
       r->per_dir_config = r->server->lookup_defaults;
  
  
  
  1.152     +1 -24     apachen/src/main/httpd.h
  
  Index: httpd.h
  ===================================================================
  RCS file: /export/home/cvs/apachen/src/main/httpd.h,v
  retrieving revision 1.151
  retrieving revision 1.152
  diff -u -r1.151 -r1.152
  --- httpd.h   1997/10/07 06:24:55     1.151
  +++ httpd.h   1997/10/07 19:34:05     1.152
  @@ -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 {
  
  
  
  1.1                  apachen/src/main/http_vhost.c
  
  Index: http_vhost.c
  ===================================================================
  /* ====================================================================
   * 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 const char *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 NULL;
  
      t = strchr(w, ':');
      if (t) {
        if (strcmp(t + 1, "*") == 0) {
            port = 0;
        }
        else if ((i = atoi(t + 1))) {
            port = i;
        }
        else {
            return ":port must be numeric";
        }
        *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 NULL;
      }
  
      hep = gethostbyname(w);
  
      if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
        aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, NULL,
            "Cannot resolve host name %s --- ignoring!", w);
        if (t != NULL)
            *t = ':';
        return NULL;
      }
  
      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 = ':';
      return NULL;
  }
  
  
  /* parse the <VirtualHost> addresses */
  const char *parse_vhost_addrs(pool *p, const char *hostname, server_rec *s)
  {
      server_addr_rec **addrs;
      const char *err;
  
      /* start the list of addreses */
      addrs = &s->addrs;
      while (hostname[0]) {
        err = get_addresses(p, getword_conf(p, &hostname), &addrs, s->port);
        if (err) {
            *addrs = NULL;
            return err;
        }
      }
      /* 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;
        }
      }
      return NULL;
  }
  
  
  const char *set_name_virtual_host (cmd_parms *cmd, void *dummy, char *arg)
  {
      /* use whatever port the main server has at this point */
      return get_addresses(cmd->pool, arg, &name_vhost_list_tail,
                            cmd->server->port);
  }
  
  
  /* 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_NOERRNO|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
                || port == 0)) {
            return trav;
        }
      }
      return NULL;
  }
  
  
  static ipaddr_chain *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;
          }
      }
      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
                 */
                ipaddr_chain *other;
  
                other = find_default_server(sar->host_port);
                if (other && other->sar->host_port != 0) {
                    aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, main_s,
                            "_default_ VirtualHost overlap on port %u,"
                            " the first has precedence", sar->host_port);
                }
                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;
                    if (sar->host_port != ic->sar->host_port) {
                        /* one of the two is a * port, the other isn't */
                        aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, main_s,
                                "VirtualHost %s:%u -- mixing * "
                                "ports and non-* ports with "
                                "a NameVirtualHost address is not supported,"
                                " you will get undefined behaviour",
                                sar->virthost, sar->host_port);
                    }
                }
                else if (ic) {
                    aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, main_s,
                            "VirtualHost %s:%u overlaps with "
                            "VirtualHost %s:%u, the first has precedence",
                            sar->virthost, sar->host_port,
                            ic->sar->virthost, ic->sar->host_port);
                    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 */
                    aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, main_s,
                            "Failed to resolve server name "
                            "for %s (check DNS) -- or specify an explicit "
                            "ServerName",
                            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) {
                aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, main_s,
                        "NameVirtualHost %s:%u has no VirtualHosts",
                        ic->sar->virthost, ic->sar->host_port);
                *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)
  {
      /*
       * Even if the request has a Host: header containing a port we ignore
       * that port.  We always use the physical port of the socket.  There
       * are a few reasons for this:
       *
       * - the default of 80 or 443 for SSL is easier to handle this way
       * - there is less of a possibility of a security problem
       * - it simplifies the data structure
       * - the client may have no idea that a proxy somewhere along the way
       *   translated the request to another ip:port
       * - except for the addresses from the VirtualHost line, none of the other
       *   names we'll match have ports associated with them
       */
      const char *hostname = r->hostname;
      char *host = getword(r->pool, &hostname, ':');      /* Get rid of port */
      unsigned port = ntohs(r->connection->local_addr.sin_port);
      server_rec *s;
      server_rec *last_s;
      size_t l;
      name_chain *src;
  
      /* trim a trailing . */
      l = strlen(host);
      if (l > 0 && host[l-1] == '.') {
          host[l-1] = '\0';
      }
  
      r->hostname = host;
      last_s = NULL;
  
      /* Recall that the name_chain is a list of server_addr_recs, some of
       * whose ports may not match.  Also each server may appear more than
       * once in the chain -- specifically, it will appear once for each
       * address from its VirtualHost line which matched.  We only want to
       * do the full ServerName/ServerAlias comparisons once for each
       * server, fortunately we know that all the VirtualHost addresses for
       * a single server are adjacent to each other.
       */
  
      for (src = r->connection->vhost_lookup_data; src; src = src->next) {
          const char *names;
          server_addr_rec *sar;
  
        /* We only consider addresses on the name_chain which have a matching
         * port
         */
        sar = src->sar;
        if (sar->host_port != 0 && port != sar->host_port) {
            continue;
        }
  
          s = src->server;
  
        /* does it match the virthost from the sar? */
        if (!strcasecmp(host, sar->virthost)) {
            goto found;
        }
  
        if (s == last_s) {
            /* we've already done ServerName and ServerAlias checks for this
             * vhost
             */
            continue;
        }
        last_s = s;
  
        /* match ServerName */
          if (!strcasecmp(host, s->server_hostname)) {
            goto found;
          }
  
          /* 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))) {
                    goto found;
                  }
              }
          }
      }
      return;
  
  found:
      /* s is the first matching server, we're done */
      r->server = r->connection->server = s;
      if (r->hostlen && !strncmp(r->uri, "http://";, 7)) {
        r->uri += r->hostlen;
        parse_uri(r, r->uri);
      }
  }
  
  
  void check_serverpath(request_rec *r)
  {
      server_rec *s;
      server_rec *last_s;
      name_chain *src;
      unsigned port = ntohs(r->connection->local_addr.sin_port);
  
      /*
       * This is in conjunction with the ServerPath code in http_core, so we
       * get the right host attached to a non- Host-sending request.
       *
       * See the comment in check_hostaliases about how each vhost can be
       * listed multiple times.
       */
  
      last_s = NULL;
      for (src = r->connection->vhost_lookup_data; src; src = src->next) {
        /* We only consider addresses on the name_chain which have a matching
         * port
         */
        if (src->sar->host_port != 0 && port != src->sar->host_port) {
            continue;
        }
  
          s = src->server;
        if (s == last_s) {
            continue;
        }
        last_s = s;
  
          if (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");
      }
  }
  
  
  /* 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);
  
      /* 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 */
      trav = find_default_server(port);
      if (trav) {
        conn->server = trav->server;
      }
  
      /* otherwise we're stuck with just the main server */
  }
  
  
  
  1.1                  apachen/src/main/http_vhost.h
  
  Index: http_vhost.h
  ===================================================================
  /* ====================================================================
   * 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 */
  const char *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
  
  
  

Reply via email to