diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/server/vhost.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/vhost.c | 1072 |
1 files changed, 0 insertions, 1072 deletions
diff --git a/rubbos/app/httpd-2.0.64/server/vhost.c b/rubbos/app/httpd-2.0.64/server/vhost.c deleted file mode 100644 index edab75a5..00000000 --- a/rubbos/app/httpd-2.0.64/server/vhost.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * http_vhost.c: functions pertaining to virtual host addresses - * (configuration and run-time) - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_vhost.h" -#include "http_protocol.h" -#include "http_core.h" - -#if APR_HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif - -/* - * 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 apr_table_t 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 */ -AP_DECLARE(void) ap_init_vhost_config(apr_pool_t *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(apr_pool_t *p, const char *w_, - server_addr_rec ***paddr, - apr_port_t default_port) -{ - apr_sockaddr_t *my_addr; - server_addr_rec *sar; - char *w, *host, *scope_id; - int wild_port; - apr_size_t wlen; - apr_port_t port; - apr_status_t rv; - - if (*w_ == '\0') - return NULL; - - w = apr_pstrdup(p, w_); - /* apr_parse_addr_port() doesn't understand ":*" so handle that first. */ - wlen = strlen(w); /* wlen must be > 0 at this point */ - wild_port = 0; - if (w[wlen - 1] == '*') { - if (wlen < 2) { - wild_port = 1; - } - else if (w[wlen - 2] == ':') { - w[wlen - 2] = '\0'; - wild_port = 1; - } - } - rv = apr_parse_addr_port(&host, &scope_id, &port, w, p); - /* If the string is "80", apr_parse_addr_port() will be happy and set - * host to NULL and port to 80, so watch out for that. - */ - if (rv != APR_SUCCESS) { - return "The address or port is invalid"; - } - if (!host) { - return "Missing address for VirtualHost"; - } - if (scope_id) { - return "Scope ids are not supported"; - } - if (!port && !wild_port) { - port = default_port; - } - - if (strcmp(host, "*") == 0) { - rv = apr_sockaddr_info_get(&my_addr, "0.0.0.0", APR_INET, port, 0, p); - ap_assert(rv == APR_SUCCESS); /* must be bug or out of storage */ - } - else if (strcasecmp(host, "_default_") == 0 - || strcmp(host, "255.255.255.255") == 0) { - rv = apr_sockaddr_info_get(&my_addr, "255.255.255.255", APR_INET, port, 0, p); - ap_assert(rv == APR_SUCCESS); /* must be bug or out of storage */ - } - else { - rv = apr_sockaddr_info_get(&my_addr, host, APR_UNSPEC, port, 0, p); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "Cannot resolve host name %s --- ignoring!", host); - return NULL; - } - } - - /* Remember all addresses for the host */ - - do { - sar = apr_pcalloc(p, sizeof(server_addr_rec)); - **paddr = sar; - *paddr = &sar->next; - sar->host_addr = my_addr; - sar->host_port = port; - sar->virthost = host; - my_addr = my_addr->next; - } while (my_addr); - - return NULL; -} - - -/* parse the <VirtualHost> addresses */ -const char *ap_parse_vhost_addrs(apr_pool_t *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, ap_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 *ap_set_name_virtual_host(cmd_parms *cmd, void *dummy, - const 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 apr_table_t 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 + apr_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 += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u", - total, count[i - 1]); - total = 1; - } - else { - ++total; - } - } - p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u", - total, count[IPHASH_TABLE_SIZE - 1]); - ap_log_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. - * - * NOTE: This function is symmetric (i.e. collapses all 4 octets - * into one), so machine byte order (big/little endianness) does not matter. - * - * Hash function provided by David Hankins. - */ -static APR_INLINE unsigned hash_inaddr(unsigned key) -{ - key ^= (key >> 16); - return ((key >> 8) ^ key) % IPHASH_TABLE_SIZE; -} - -static APR_INLINE unsigned hash_addr(struct apr_sockaddr_t *sa) -{ - unsigned key; - - /* The key is the last four bytes of the IP address. - * For IPv4, this is the entire address, as always. - * For IPv6, this is usually part of the MAC address. - */ - key = *(unsigned *)((char *)sa->ipaddr_ptr + sa->ipaddr_len - 4); - return hash_inaddr(key); -} - -static ipaddr_chain *new_ipaddr_chain(apr_pool_t *p, - server_rec *s, server_addr_rec *sar) -{ - ipaddr_chain *new; - - new = apr_palloc(p, sizeof(*new)); - new->names = NULL; - new->server = s; - new->sar = sar; - new->next = NULL; - return new; -} - - -static name_chain *new_name_chain(apr_pool_t *p, - server_rec *s, server_addr_rec *sar) -{ - name_chain *new; - - new = apr_palloc(p, sizeof(*new)); - new->server = s; - new->sar = sar; - new->next = NULL; - return new; -} - - -static APR_INLINE ipaddr_chain *find_ipaddr(apr_sockaddr_t *sa) -{ - unsigned bucket; - ipaddr_chain *trav; - - /* scan the hash apr_table_t for an exact match first */ - bucket = hash_addr(sa); - for (trav = iphash_table[bucket]; trav; trav = trav->next) { - server_addr_rec *sar = trav->sar; - apr_sockaddr_t *cur = sar->host_addr; - - if (cur->port == 0 || sa->port == 0 || cur->port == sa->port) { - if (apr_sockaddr_equal(cur, sa)) { - return trav; - } - } - } - return NULL; -} - -static ipaddr_chain *find_default_server(apr_port_t 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; -} - -static void dump_a_vhost(apr_file_t *f, ipaddr_chain *ic) -{ - name_chain *nc; - int len; - char buf[MAX_STRING_LEN]; - apr_sockaddr_t *ha = ic->sar->host_addr; - - if (ha->family == APR_INET && - ha->sa.sin.sin_addr.s_addr == DEFAULT_VHOST_ADDR) { - len = apr_snprintf(buf, sizeof(buf), "_default_:%u", - ic->sar->host_port); - } - else if (ha->family == APR_INET && - ha->sa.sin.sin_addr.s_addr == INADDR_ANY) { - len = apr_snprintf(buf, sizeof(buf), "*:%u", - ic->sar->host_port); - } - else { - len = apr_snprintf(buf, sizeof(buf), "%pI", ha); - } - if (ic->sar->host_port == 0) { - buf[len-1] = '*'; - } - if (ic->names == NULL) { - apr_file_printf(f, "%-22s %s (%s:%u)\n", buf, - ic->server->server_hostname, - ic->server->defn_name, ic->server->defn_line_number); - return; - } - apr_file_printf(f, "%-22s is a NameVirtualHost\n" - "%8s default server %s (%s:%u)\n", - buf, "", ic->server->server_hostname, - ic->server->defn_name, ic->server->defn_line_number); - for (nc = ic->names; nc; nc = nc->next) { - if (nc->sar->host_port) { - apr_file_printf(f, "%8s port %u ", "", nc->sar->host_port); - } - else { - apr_file_printf(f, "%8s port * ", ""); - } - apr_file_printf(f, "namevhost %s (%s:%u)\n", - nc->server->server_hostname, - nc->server->defn_name, nc->server->defn_line_number); - } -} - -static void dump_vhost_config(apr_file_t *f) -{ - ipaddr_chain *ic; - int i; - - apr_file_printf(f, "VirtualHost configuration:\n"); - for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { - for (ic = iphash_table[i]; ic; ic = ic->next) { - dump_a_vhost(f, ic); - } - } - if (default_list) { - apr_file_printf(f, "wildcard NameVirtualHosts and _default_ servers:\n"); - for (ic = default_list; ic; ic = ic->next) { - dump_a_vhost(f, ic); - } - } -} - -/* - * Two helper functions for ap_fini_vhost_config() - */ -static int add_name_vhost_config(apr_pool_t *p, server_rec *main_s, - server_rec *s, server_addr_rec *sar, - ipaddr_chain *ic) -{ - /* the first time we encounter a NameVirtualHost address - * ic->server will be NULL, on subsequent encounters - * ic->names will be non-NULL. - */ - if (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 */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_s, - "VirtualHost %s:%u -- mixing * " - "ports and non-* ports with " - "a NameVirtualHost address is not supported," - " proceeding with undefined results", - sar->virthost, sar->host_port); - } - return 1; - } - else { - /* IP-based vhosts are handled by the caller */ - return 0; - } -} - -static void remove_unused_name_vhosts(server_rec *main_s, ipaddr_chain **pic) -{ - while (*pic) { - ipaddr_chain *ic = *pic; - - if (ic->server == NULL) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, 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; - } - } -} - -/* compile the tables and such we need to do the run-time vhost lookups */ -AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *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 = ap_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 apr_table_t 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) { - char inaddr_any[16] = {0}; /* big enough to handle IPv4 or IPv6 */ - unsigned bucket = hash_addr(sar->host_addr); - ipaddr_chain *ic = new_ipaddr_chain(p, NULL, sar); - - if (memcmp(sar->host_addr->ipaddr_ptr, inaddr_any, - sar->host_addr->ipaddr_len)) { /* not IN[6]ADDR_ANY */ - *iphash_table_tail[bucket] = ic; - iphash_table_tail[bucket] = &ic->next; - } - else { - /* A wildcard NameVirtualHost goes on the default_list so - * that it can catch incoming requests on any address. - */ - ic->next = default_list; - default_list = ic; - } - /* Notice that what we've done is insert an ipaddr_chain with - * both server and names NULL. This fact is used to spot name- - * based vhosts in add_name_vhost_config(). - */ - } - - /* The next things to go into the hash apr_table_t 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; - char inaddr_any[16] = {0}; /* big enough to handle IPv4 or IPv6 */ - - if ((sar->host_addr->family == AF_INET && - sar->host_addr->sa.sin.sin_addr.s_addr == DEFAULT_VHOST_ADDR) - || !memcmp(sar->host_addr->ipaddr_ptr, inaddr_any, sar->host_addr->ipaddr_len)) { - ic = find_default_server(sar->host_port); - if (!ic || !add_name_vhost_config(p, main_s, s, sar, ic)) { - if (ic && ic->sar->host_port != 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, - 0, main_s, "_default_ VirtualHost " - "overlap on port %u, the first has " - "precedence", sar->host_port); - } - ic = new_ipaddr_chain(p, s, sar); - ic->next = default_list; - default_list = ic; - } - has_default_vhost_addr = 1; - } - else { - /* see if it matches something we've already got */ - ic = find_ipaddr(sar->host_addr); - - if (!ic) { - unsigned bucket = hash_addr(sar->host_addr); - - ic = new_ipaddr_chain(p, s, sar); - ic->next = *iphash_table_tail[bucket]; - *iphash_table_tail[bucket] = ic; - } - else if (!add_name_vhost_config(p, main_s, s, sar, ic)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, - 0, main_s, "VirtualHost %s:%u overlaps " - "with VirtualHost %s:%u, the first has " - "precedence, perhaps you need a " - "NameVirtualHost directive", - sar->virthost, sar->host_port, - ic->sar->virthost, ic->sar->host_port); - ic->sar = sar; - ic->server = s; - } - } - } - - /* 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 = - apr_pstrdup(p, "bogus_host_without_forward_dns"); - } - else { - apr_status_t rv; - char *hostname; - - rv = apr_getnameinfo(&hostname, s->addrs->host_addr, 0); - if (rv == APR_SUCCESS) { - s->server_hostname = apr_pstrdup(p, hostname); - } - else { - /* again, what can we do? They didn't specify a - ServerName, and their DNS isn't working. -djg */ - char *ipaddr_str; - - apr_sockaddr_ip_get(&ipaddr_str, s->addrs->host_addr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_s, - "Failed to resolve server name " - "for %s (check DNS) -- or specify an explicit " - "ServerName", - ipaddr_str); - s->server_hostname = - apr_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) { - remove_unused_name_vhosts(main_s, &iphash_table[i]); - } - remove_unused_name_vhosts(main_s, &default_list); - -#ifdef IPHASH_STATISTICS - dump_iphash_statistics(main_s); -#endif - if (ap_exists_config_define("DUMP_VHOSTS")) { - apr_file_t *thefile = NULL; - apr_file_open_stderr(&thefile, p); - dump_vhost_config(thefile); - } -} - - -/***************************************************************************** - * run-time vhost matching functions - */ - -/* Lowercase and remove any trailing dot and/or :port from the hostname, - * and check that it is sane. - * - * In most configurations the exact syntax of the hostname isn't - * important so strict sanity checking isn't necessary. However, in - * mass hosting setups (using mod_vhost_alias or mod_rewrite) where - * the hostname is interpolated into the filename, we need to be sure - * that the interpolation doesn't expose parts of the filesystem. - * We don't do strict RFC 952 / RFC 1123 syntax checking in order - * to support iDNS and people who erroneously use underscores. - * Instead we just check for filesystem metacharacters: directory - * separators / and \ and sequences of more than one dot. - */ -static void fix_hostname(request_rec *r) -{ - char *host, *scope_id; - char *dst; - apr_port_t port; - apr_status_t rv; - - /* According to RFC 2616, Host header field CAN be blank. */ - if (!*r->hostname) { - return; - } - - rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); - if (rv != APR_SUCCESS || scope_id) { - goto bad; - } - - if (!host && port) { - /* silly looking host ("Host: 123") but that isn't our job - * here to judge; apr_parse_addr_port() would think we had a port - * but no address - */ - host = apr_itoa(r->pool, (int)port); - } - else if (port) { - /* Don't throw the Host: header's port number away: - save it in parsed_uri -- ap_get_server_port() needs it! */ - /* @@@ XXX there should be a better way to pass the port. - * Like r->hostname, there should be a r->portno - */ - r->parsed_uri.port = port; - r->parsed_uri.port_str = apr_itoa(r->pool, (int)port); - } - - /* if the hostname is an IPv6 numeric address string, it was validated - * already; otherwise, further validation is needed - */ - if (r->hostname[0] != '[') { - for (dst = host; *dst; dst++) { - if (apr_islower(*dst)) { - /* leave char unchanged */ - } - else if (*dst == '.') { - if (*(dst + 1) == '.') { - goto bad; - } - } - else if (apr_isupper(*dst)) { - *dst = apr_tolower(*dst); - } - else if (*dst == '/' || *dst == '\\') { - goto bad; - } - } - /* strip trailing gubbins */ - if (dst > host && dst[-1] == '.') { - dst[-1] = '\0'; - } - } - r->hostname = host; - return; - -bad: - r->status = HTTP_BAD_REQUEST; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Client sent malformed Host header"); - return; -} - - -/* return 1 if host matches ServerName or ServerAliases */ -static int matches_aliases(server_rec *s, const char *host) -{ - int i; - apr_array_header_t *names; - - /* match ServerName */ - if (!strcasecmp(host, s->server_hostname)) { - return 1; - } - - /* search all the aliases from ServerAlias directive */ - names = s->names; - if (names) { - char **name = (char **) names->elts; - for (i = 0; i < names->nelts; ++i) { - if(!name[i]) continue; - if (!strcasecmp(host, name[i])) - return 1; - } - } - names = s->wild_names; - if (names) { - char **name = (char **) names->elts; - for (i = 0; i < names->nelts; ++i) { - if(!name[i]) continue; - if (!ap_strcasecmp_match(host, name[i])) - return 1; - } - } - return 0; -} - - -/* Suppose a request came in on the same socket as this r, and included - * a header "Host: host:port", would it map to r->server? It's more - * than just that though. When we do the normal matches for each request - * we don't even bother considering Host: etc on non-namevirtualhosts, - * we just call it a match. But here we require the host:port to match - * the ServerName and/or ServerAliases. - */ -AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host, - apr_port_t port) -{ - server_rec *s; - server_addr_rec *sar; - - s = r->server; - - /* search all the <VirtualHost> values */ - /* XXX: If this is a NameVirtualHost then we may not be doing the Right Thing - * consider: - * - * NameVirtualHost 10.1.1.1 - * <VirtualHost 10.1.1.1> - * ServerName v1 - * </VirtualHost> - * <VirtualHost 10.1.1.1> - * ServerName v2 - * </VirtualHost> - * - * Suppose r->server is v2, and we're asked to match "10.1.1.1". We'll say - * "yup it's v2", when really it isn't... if a request came in for 10.1.1.1 - * it would really go to v1. - */ - for (sar = s->addrs; sar; sar = sar->next) { - if ((sar->host_port == 0 || port == sar->host_port) - && !strcasecmp(host, sar->virthost)) { - return 1; - } - } - - /* the Port has to match now, because the rest don't have ports associated - * with them. */ - if (port != s->port) { - return 0; - } - - return matches_aliases(s, host); -} - - -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 *host = r->hostname; - apr_port_t port; - server_rec *s; - server_rec *last_s; - name_chain *src; - - last_s = NULL; - - apr_sockaddr_port_get(&port, r->connection->local_addr); - - /* 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) { - 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; - - if (matches_aliases(s, host)) { - goto found; - } - } - return; - -found: - /* s is the first matching server, we're done */ - r->server = s; -} - - -static void check_serverpath(request_rec *r) -{ - server_rec *s; - server_rec *last_s; - name_chain *src; - apr_port_t port; - - apr_sockaddr_port_get(&port, r->connection->local_addr); - - /* - * 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_hostalias 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 = s; - return; - } - } -} - - -AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) -{ - /* must set this for HTTP/1.1 support */ - if (r->hostname || (r->hostname = apr_table_get(r->headers_in, "Host"))) { - fix_hostname(r); - if (r->status != HTTP_OK) - return; - } - /* check if we tucked away a name_chain */ - if (r->connection->vhost_lookup_data) { - if (r->hostname) - check_hostalias(r); - else - check_serverpath(r); - } -} - - -/** - * For every virtual host on this connection, call func_cb. - */ -AP_DECLARE(int) ap_vhost_iterate_given_conn(conn_rec *conn, - ap_vhost_iterate_conn_cb func_cb, - void* baton) -{ - server_rec *s; - server_rec *last_s; - name_chain *src; - apr_port_t port; - int rv = 0; - - if (conn->vhost_lookup_data) { - last_s = NULL; - port = conn->local_addr->port; - - for (src = conn->vhost_lookup_data; src; src = src->next) { - 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; - - if (s == last_s) { - /* we've already done a callback for this vhost. */ - continue; - } - - last_s = s; - - rv = func_cb(baton, conn, s); - - if (rv != 0) { - break; - } - } - } - else { - rv = func_cb(baton, conn, conn->base_server); - } - - return rv; -} - -/* Called for a new connection which has a known local_addr. Note that the - * new connection is assumed to have conn->server == main server. - */ -AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn) -{ - ipaddr_chain *trav; - apr_port_t port; - - /* scan the hash apr_table_t for an exact match first */ - trav = find_ipaddr(conn->local_addr); - - if (trav) { - /* save the name_chain for later in case this is a name-vhost */ - conn->vhost_lookup_data = trav->names; - conn->base_server = trav->server; - return; - } - - /* maybe there's a default server or wildcard name-based vhost - * matching this port - */ - apr_sockaddr_port_get(&port, conn->local_addr); - - trav = find_default_server(port); - if (trav) { - conn->vhost_lookup_data = trav->names; - conn->base_server = trav->server; - return; - } - - /* otherwise we're stuck with just the main server - * and no name-based vhosts - */ - conn->vhost_lookup_data = NULL; -} |