⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vhost.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************************************************** * 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);    }}/* 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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -