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

📄 mod_proxy.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed 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. */#define CORE_PRIVATE#include "mod_proxy.h"#include "mod_core.h"#include "apr_optional.h"#ifndef MAX#define MAX(x,y) ((x) >= (y) ? (x) : (y))#endif/* * A Web proxy module. Stages: * *  translate_name: set filename to proxy:<URL> *  map_to_storage: run proxy_walk (rather than directory_walk/file_walk) *                  can't trust directory_walk/file_walk since these are *                  not in our filesystem.  Prevents mod_http from serving *                  the TRACE request we will set aside to handle later. *  type_checker:   set type to PROXY_MAGIC_TYPE if filename begins proxy: *  fix_ups:        convert the URL stored in the filename to the *                  canonical form. *  handler:        handle proxy requests *//* -------------------------------------------------------------- *//* Translate the URL into a 'filename' */static int alias_match(const char *uri, const char *alias_fakename){    const char *end_fakename = alias_fakename + strlen(alias_fakename);    const char *aliasp = alias_fakename, *urip = uri;    while (aliasp < end_fakename) {        if (*aliasp == '/') {            /* any number of '/' in the alias matches any number in             * the supplied URI, but there must be at least one...             */            if (*urip != '/')                return 0;            while (*aliasp == '/')                ++aliasp;            while (*urip == '/')                ++urip;        }        else {            /* Other characters are compared literally */            if (*urip++ != *aliasp++)                return 0;        }    }    /* Check last alias path component matched all the way */    if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')        return 0;    /* Return number of characters from URI which matched (may be     * greater than length of alias, since we may have matched     * doubled slashes)     */    return urip - uri;}/* Detect if an absoluteURI should be proxied or not.  Note that we * have to do this during this phase because later phases are * "short-circuiting"... i.e. translate_names will end when the first * module returns OK.  So for example, if the request is something like: * * GET http://othervhost/cgi-bin/printenv HTTP/1.0 * * mod_alias will notice the /cgi-bin part and ScriptAlias it and * short-circuit the proxy... just because of the ordering in the * configuration file. */static int proxy_detect(request_rec *r){    void *sconf = r->server->module_config;    proxy_server_conf *conf;    conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    /* Ick... msvc (perhaps others) promotes ternary short results to int */    if (conf->req && r->parsed_uri.scheme) {        /* but it might be something vhosted */        if (!(r->parsed_uri.hostname              && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))              && ap_matches_request_vhost(r, r->parsed_uri.hostname,                                          (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port                                                        : ap_default_port(r))))) {            r->proxyreq = PROXYREQ_PROXY;            r->uri = r->unparsed_uri;            r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);            r->handler = "proxy-server";        }    }    /* We need special treatment for CONNECT proxying: it has no scheme part */    else if (conf->req && r->method_number == M_CONNECT             && r->parsed_uri.hostname             && r->parsed_uri.port_str) {        r->proxyreq = PROXYREQ_PROXY;        r->uri = r->unparsed_uri;        r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);        r->handler = "proxy-server";    }    return DECLINED;}static int proxy_trans(request_rec *r){    void *sconf = r->server->module_config;    proxy_server_conf *conf =    (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    int i, len;    struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;    if (r->proxyreq) {        /* someone has already set up the proxy, it was possibly ourselves         * in proxy_detect         */        return OK;    }    /* XXX: since r->uri has been manipulated already we're not really     * compliant with RFC1945 at this point.  But this probably isn't     * an issue because this is a hybrid proxy/origin server.     */    for (i = 0; i < conf->aliases->nelts; i++) {        len = alias_match(r->uri, ent[i].fake);       if (len > 0) {           if ((ent[i].real[0] == '!' ) && ( ent[i].real[1] == 0 )) {               return DECLINED;           }           r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,                                 (r->uri + len ), NULL);           r->handler = "proxy-server";           r->proxyreq = PROXYREQ_REVERSE;           return OK;       }    }    return DECLINED;}static int proxy_walk(request_rec *r){    proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,                                                    &proxy_module);    ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;    ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts;    ap_conf_vector_t *entry_config;    proxy_dir_conf *entry_proxy;    int num_sec = sconf->sec_proxy->nelts;    /* XXX: shouldn't we use URI here?  Canonicalize it first?     * Pass over "proxy:" prefix      */    const char *proxyname = r->filename + 6;    int j;    for (j = 0; j < num_sec; ++j)     {        entry_config = sec_proxy[j];        entry_proxy = ap_get_module_config(entry_config, &proxy_module);        /* XXX: What about case insensitive matching ???         * Compare regex, fnmatch or string as appropriate         * If the entry doesn't relate, then continue          */        if (entry_proxy->r               ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0)              : (entry_proxy->p_is_fnmatch                   ? apr_fnmatch(entry_proxy->p, proxyname, 0)                   : strncmp(proxyname, entry_proxy->p,                                         strlen(entry_proxy->p)))) {            continue;        }        per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,                                                             entry_config);    }    r->per_dir_config = per_dir_defaults;    return OK;}static int proxy_map_location(request_rec *r){    int access_status;    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)        return DECLINED;    /* Don't let the core or mod_http map_to_storage hooks handle this,     * We don't need directory/file_walk, and we want to TRACE on our own.     */    if ((access_status = proxy_walk(r))) {        ap_die(access_status, r);        return access_status;    }    return OK;}/* -------------------------------------------------------------- *//* Fixup the filename *//* * Canonicalise the URL */static int proxy_fixup(request_rec *r){    char *url, *p;    int access_status;    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)        return DECLINED;    /* XXX: Shouldn't we try this before we run the proxy_walk? */    url = &r->filename[6];    /* canonicalise each specific scheme */    if ((access_status = proxy_run_canon_handler(r, url))) {        return access_status;    }    p = strchr(url, ':');    if (p == NULL || p == url)        return HTTP_BAD_REQUEST;    return OK;		/* otherwise; we've done the best we can */}/* Send a redirection if the request contains a hostname which is not *//* fully qualified, i.e. doesn't have a domain name appended. Some proxy *//* servers like Netscape's allow this and access hosts from the local *//* domain in this case. I think it is better to redirect to a FQDN, since *//* these will later be found in the bookmarks files. *//* The "ProxyDomain" directive determines what domain will be appended */static int proxy_needsdomain(request_rec *r, const char *url, const char *domain){    char *nuri;    const char *ref;    /* We only want to worry about GETs */    if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)        return DECLINED;    /* If host does contain a dot already, or it is "localhost", decline */    if (strchr(r->parsed_uri.hostname, '.') != NULL     || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)        return DECLINED;	/* host name has a dot already */    ref = apr_table_get(r->headers_in, "Referer");    /* Reassemble the request, but insert the domain after the host name */    /* Note that the domain name always starts with a dot */    r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname,                                         domain, NULL);    nuri = apr_uri_unparse(r->pool,                           &r->parsed_uri,                           APR_URI_UNP_REVEALPASSWORD);    apr_table_set(r->headers_out, "Location", nuri);    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,                  "Domain missing: %s sent to %s%s%s", r->uri,                  apr_uri_unparse(r->pool, &r->parsed_uri,                                  APR_URI_UNP_OMITUSERINFO),                  ref ? " from " : "", ref ? ref : "");    return HTTP_MOVED_PERMANENTLY;}/* -------------------------------------------------------------- *//* Invoke handler */static int proxy_handler(request_rec *r){    char *url, *scheme, *p;    const char *p2;    void *sconf = r->server->module_config;    proxy_server_conf *conf = (proxy_server_conf *)        ap_get_module_config(sconf, &proxy_module);    apr_array_header_t *proxies = conf->proxies;    struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;    int i, rc, access_status;    int direct_connect = 0;    const char *str;    long maxfwd;    /* is this for us? */    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)        return DECLINED;    /* handle max-forwards / OPTIONS / TRACE */    if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) {        maxfwd = strtol(str, NULL, 10);        if (maxfwd < 1) {            switch (r->method_number) {            case M_TRACE: {                int access_status;                r->proxyreq = PROXYREQ_NONE;                if ((access_status = ap_send_http_trace(r)))                    ap_die(access_status, r);                else                    ap_finalize_request_protocol(r);                return OK;            }            case M_OPTIONS: {                int access_status;                r->proxyreq = PROXYREQ_NONE;                if ((access_status = ap_send_http_options(r)))                    ap_die(access_status, r);                else                    ap_finalize_request_protocol(r);                return OK;            }            default: {                return ap_proxyerror(r, HTTP_BAD_GATEWAY,                                     "Max-Forwards has reached zero - proxy loop?");            }            }        }        maxfwd = (maxfwd > 0) ? maxfwd - 1 : 0;    }    else {        /* set configured max-forwards */        maxfwd = conf->maxfwd;    }    apr_table_set(r->headers_in, "Max-Forwards",                   apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));    url = r->filename + 6;    p = strchr(url, ':');    if (p == NULL)        return HTTP_BAD_REQUEST;    /* If the host doesn't have a domain name, add one and redirect. */    if (conf->domain != NULL) {        rc = proxy_needsdomain(r, url, conf->domain);        if (ap_is_HTTP_REDIRECT(rc))            return HTTP_MOVED_PERMANENTLY;    }    *p = '\0';    scheme = apr_pstrdup(r->pool, url);    *p = ':';    /* Check URI's destination host against NoProxy hosts */    /* Bypass ProxyRemote server lookup if configured as NoProxy */    /* we only know how to handle communication to a proxy via http */    /*if (strcasecmp(scheme, "http") == 0) */    {        int ii;        struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;

⌨️ 快捷键说明

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