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

📄 mod_proxy.c

📁 精通tomcat书籍原代码,希望大家共同学习
💻 C
📖 第 1 页 / 共 5 页
字号:
#define FIX_15207
/* Copyright 1999-2004 The Apache Software Foundation
 *
 * 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"
#include "mod_status.h"

#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
#include "mod_ssl.h"
#else
APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
#endif

#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' */

#ifdef FIX_15207
/* XXX: EBCDIC safe? --nd */
#define x2c(x) (((x >= '0') && (x <= '9'))         \
                   ? (x - '0')                     \
                   : (((x >= 'a') && (x <= 'f'))   \
                       ? (10 + x - 'a')            \
                       : ((x >= 'A') && (x <='F')) \
                           ? (10 + x - 'A')        \
                           : 0                     \
                     )                             \
               )

static unsigned char hex2c(const char* p) {
  const char c1 = p[1];
  const char c2 = p[1] ? p[2]: '\0';
  int i1 = c1 ? x2c(c1) : 0;
  int i2 = c2 ? x2c(c2) : 0;
  unsigned char ret = (i1 << 4) | i2;

  return ret;
}
#endif

#define PROXY_COPY_CONF_PARAMS(w, c) \
    do {                             \
        (w)->timeout              = (c)->timeout;               \
        (w)->timeout_set          = (c)->timeout_set;           \
        (w)->recv_buffer_size     = (c)->recv_buffer_size;      \
        (w)->recv_buffer_size_set = (c)->recv_buffer_size_set;  \
        (w)->io_buffer_size       = (c)->io_buffer_size;        \
        (w)->io_buffer_size_set   = (c)->io_buffer_size_set;    \
    } while (0)

static const char *set_worker_param(apr_pool_t *p,
                                    proxy_worker *worker,
                                    const char *key,
                                    const char *val)
{

    int ival;
    if (!strcasecmp(key, "loadfactor")) {
        worker->lbfactor = atoi(val);
        if (worker->lbfactor < 1 || worker->lbfactor > 100)
            return "LoadFactor must be number between 1..100";
    }
    else if (!strcasecmp(key, "retry")) {
        ival = atoi(val);
        if (ival < 1)
            return "Retry must be at least one second";
        worker->retry = apr_time_from_sec(ival);
    }
    else if (!strcasecmp(key, "ttl")) {
        ival = atoi(val);
        if (ival < 1)
            return "TTL must be at least one second";
        worker->ttl = apr_time_from_sec(ival);
    }
    else if (!strcasecmp(key, "min")) {
        ival = atoi(val);
        if (ival < 0)
            return "Min must be a positive number";
        worker->min = ival;
    }
    else if (!strcasecmp(key, "max")) {
        ival = atoi(val);
        if (ival < 0)
            return "Max must be a positive number";
        worker->hmax = ival;
    }
    /* XXX: More inteligent naming needed */
    else if (!strcasecmp(key, "smax")) {
        ival = atoi(val);
        if (ival < 0)
            return "Smax must be a positive number";
        worker->smax = ival;
    }
    else if (!strcasecmp(key, "acquire")) {
        ival = atoi(val);
        if (ival < 1)
            return "Acquire must be at least one mili second";
        worker->acquire = apr_time_make(0, ival * 1000);
        worker->acquire_set = 1;
    }
    else if (!strcasecmp(key, "timeout")) {
        ival = atoi(val);
        if (ival < 1)
            return "Timeout must be at least one second";
        worker->timeout = apr_time_from_sec(ival);
        worker->timeout_set = 1;
    }
    else if (!strcasecmp(key, "iobuffersize")) {
        long s = atol(val);
        worker->io_buffer_size = ((s > AP_IOBUFSIZE) ? s : AP_IOBUFSIZE);
        worker->io_buffer_size_set = 1;
    }
    else if (!strcasecmp(key, "receivebuffersize")) {
        ival = atoi(val);
        if (ival < 512 && ival != 0) {
            return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
        }
        worker->recv_buffer_size = ival;
        worker->recv_buffer_size_set = 1;
    }
    else if (!strcasecmp(key, "keepalive")) {
        if (!strcasecmp(val, "on"))
            worker->keepalive = 1;
        else if (!strcasecmp(val, "off"))
            worker->keepalive = 0;
        else
            return "KeepAlive must be On|Off";
        worker->keepalive_set = 1;
    }    
    else if (!strcasecmp(key, "route")) {
        worker->route = apr_pstrdup(p, val);
    }
    else if (!strcasecmp(key, "redirect")) {
        worker->redirect = apr_pstrdup(p, val);
    }
    else {
        return "unknown parameter";
    }
    return NULL;
}

static const char *set_balancer_param(apr_pool_t *p,
                                      proxy_balancer *balancer,
                                      const char *key,
                                      const char *val)
{

    int ival;
    if (!strcasecmp(key, "stickysession")) {
        balancer->sticky = apr_pstrdup(p, val);
    }
    else if (!strcasecmp(key, "nofailover")) {
        if (!strcasecmp(val, "on"))
            balancer->sticky_force = 1;
        else if (!strcasecmp(val, "off"))
            balancer->sticky_force = 0;
        else
            return "failover must be On|Off";
    }
    else if (!strcasecmp(key, "timeout")) {
        ival = atoi(val);
        if (ival < 1)
            return "timeout must be at least one second";
        balancer->timeout = apr_time_from_sec(ival);
    }
    else {
        return "unknown parameter";
    }
    return NULL;
}

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;
    const char *end_uri = uri + strlen(uri);
    unsigned char uric, aliasc;

    while (aliasp < end_fakename && urip < end_uri) {
        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 {
#ifndef FIX_15207
            /* Other characters are compared literally */
            if (*urip++ != *aliasp++)
                return 0;
#else
            /* Other characters are canonicalised and compared literally */
            if (*urip == '%') {
                uric = hex2c(urip);
                urip += 3;
            } else {
                uric = (unsigned char)*urip++;
            }
            if (*aliasp == '%') {
                aliasc = hex2c(aliasp);
                aliasp += 3;
            } else {
                aliasc = (unsigned char)*aliasp++;
            }
            if (uric != aliasc) {
                return 0;
            }
#endif
        }
    }

    /* fixup badly encoded stuff (e.g. % as last character) */
    if (aliasp > end_fakename) {
        aliasp = end_fakename;
    }
    if (urip > end_uri) {
        urip = end_uri;
    }

    /* 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 =
        (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
#ifdef FIX_15207
    int i, len;
    struct proxy_alias *ent = (struct proxy_alias *)conf->aliases->elts;
#endif

    /* 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";
#ifdef FIX_15207
    } else {
        /* test for a ProxyPass */
        for (i = 0; i < conf->aliases->nelts; i++) {
            len = alias_match(r->unparsed_uri, ent[i].fake);
            if (len > 0) {
                r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
                                          r->unparsed_uri + len, NULL);
                r->handler = "proxy-server";
                r->proxyreq = PROXYREQ_REVERSE;
                r->uri = r->unparsed_uri;
                break;
            }
        }
#endif
    }
    return DECLINED;
}

static int proxy_trans(request_rec *r)
{
#ifndef FIX_15207
    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;
#endif

⌨️ 快捷键说明

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