Blame modules/proxy/mod_proxy.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "mod_proxy.h"
Packit 90a5c9
#include "mod_core.h"
Packit 90a5c9
#include "apr_optional.h"
Packit 90a5c9
#include "scoreboard.h"
Packit 90a5c9
#include "mod_status.h"
Packit 90a5c9
#include "proxy_util.h"
Packit 90a5c9
Packit 90a5c9
#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
Packit 90a5c9
#include "mod_ssl.h"
Packit 90a5c9
#else
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *,
Packit 90a5c9
                                              ap_conf_vector_t *,
Packit 90a5c9
                                              int proxy, int enable));
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
Packit 90a5c9
APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
Packit 90a5c9
                        (apr_pool_t *, server_rec *,
Packit 90a5c9
                         conn_rec *, request_rec *, char *));
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifndef MAX
Packit 90a5c9
#define MAX(x,y) ((x) >= (y) ? (x) : (y))
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * We do health-checks only if that (sub)module is loaded in. This
Packit 90a5c9
 * allows for us to continue as is w/o requiring mod_watchdog for
Packit 90a5c9
 * those implementations which aren't using health checks
Packit 90a5c9
 */
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(set_worker_hc_param) *set_worker_hc_param_f = NULL;
Packit 90a5c9
Packit 90a5c9
/* Externals */
Packit 90a5c9
proxy_hcmethods_t PROXY_DECLARE_DATA proxy_hcmethods[] = {
Packit 90a5c9
    {NONE, "NONE", 1},
Packit 90a5c9
    {TCP, "TCP", 1},
Packit 90a5c9
    {OPTIONS, "OPTIONS", 1},
Packit 90a5c9
    {HEAD, "HEAD", 1},
Packit 90a5c9
    {GET, "GET", 1},
Packit 90a5c9
    {CPING, "CPING", 0},
Packit 90a5c9
    {PROVIDER, "PROVIDER", 0},
Packit 90a5c9
    {EOT, NULL, 1}
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
proxy_wstat_t PROXY_DECLARE_DATA proxy_wstat_tbl[] = {
Packit 90a5c9
    {PROXY_WORKER_INITIALIZED,   PROXY_WORKER_INITIALIZED_FLAG,   "Init "},
Packit 90a5c9
    {PROXY_WORKER_IGNORE_ERRORS, PROXY_WORKER_IGNORE_ERRORS_FLAG, "Ign "},
Packit 90a5c9
    {PROXY_WORKER_DRAIN,         PROXY_WORKER_DRAIN_FLAG,         "Drn "},
Packit 90a5c9
    {PROXY_WORKER_GENERIC,       PROXY_WORKER_GENERIC_FLAG,       "Gen "},
Packit 90a5c9
    {PROXY_WORKER_IN_SHUTDOWN,   PROXY_WORKER_IN_SHUTDOWN_FLAG,   "Shut "},
Packit 90a5c9
    {PROXY_WORKER_DISABLED,      PROXY_WORKER_DISABLED_FLAG,      "Dis "},
Packit 90a5c9
    {PROXY_WORKER_STOPPED,       PROXY_WORKER_STOPPED_FLAG,       "Stop "},
Packit 90a5c9
    {PROXY_WORKER_IN_ERROR,      PROXY_WORKER_IN_ERROR_FLAG,      "Err "},
Packit 90a5c9
    {PROXY_WORKER_HOT_STANDBY,   PROXY_WORKER_HOT_STANDBY_FLAG,   "Stby "},
Packit 90a5c9
    {PROXY_WORKER_HOT_SPARE,     PROXY_WORKER_HOT_SPARE_FLAG,     "Spar "},
Packit 90a5c9
    {PROXY_WORKER_FREE,          PROXY_WORKER_FREE_FLAG,          "Free "},
Packit 90a5c9
    {PROXY_WORKER_HC_FAIL,       PROXY_WORKER_HC_FAIL_FLAG,       "HcFl "},
Packit 90a5c9
    {0x0, '\0', NULL}
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static const char * const proxy_id = "proxy";
Packit 90a5c9
apr_global_mutex_t *proxy_mutex = NULL;
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * A Web proxy module. Stages:
Packit 90a5c9
 *
Packit 90a5c9
 *  translate_name: set filename to proxy:<URL>
Packit 90a5c9
 *  map_to_storage: run proxy_walk (rather than directory_walk/file_walk)
Packit 90a5c9
 *                  can't trust directory_walk/file_walk since these are
Packit 90a5c9
 *                  not in our filesystem.  Prevents mod_http from serving
Packit 90a5c9
 *                  the TRACE request we will set aside to handle later.
Packit 90a5c9
 *  fix_ups:        convert the URL stored in the filename to the
Packit 90a5c9
 *                  canonical form.
Packit 90a5c9
 *  handler:        handle proxy requests
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* -------------------------------------------------------------- */
Packit 90a5c9
/* Translate the URL into a 'filename' */
Packit 90a5c9
Packit 90a5c9
static const char *set_worker_param(apr_pool_t *p,
Packit 90a5c9
                                    server_rec *s,
Packit 90a5c9
                                    proxy_worker *worker,
Packit 90a5c9
                                    const char *key,
Packit 90a5c9
                                    const char *val)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    int ival;
Packit 90a5c9
    apr_interval_time_t timeout;
Packit 90a5c9
Packit 90a5c9
    if (!strcasecmp(key, "loadfactor")) {
Packit 90a5c9
        /* Normalized load factor. Used with BalancerMember,
Packit 90a5c9
         * it is a number between 1 and 100.
Packit 90a5c9
         */
Packit 90a5c9
        double fval = atof(val);
Packit 90a5c9
        ival = fval * 100.0;
Packit 90a5c9
        if (ival < 100 || ival > 10000)
Packit 90a5c9
            return "LoadFactor must be a number between 1..100";
Packit 90a5c9
        worker->s->lbfactor = ival;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "retry")) {
Packit 90a5c9
        /* If set it will give the retry timeout for the worker
Packit 90a5c9
         * The default value is 60 seconds, meaning that if
Packit 90a5c9
         * in error state, it will be retried after that timeout.
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 0)
Packit 90a5c9
            return "Retry must be a positive value";
Packit 90a5c9
        worker->s->retry = apr_time_from_sec(ival);
Packit 90a5c9
        worker->s->retry_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "ttl")) {
Packit 90a5c9
        /* Time in seconds that will destroy all the connections
Packit 90a5c9
         * that exceed the smax
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 1)
Packit 90a5c9
            return "TTL must be at least one second";
Packit 90a5c9
        worker->s->ttl = apr_time_from_sec(ival);
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "min")) {
Packit 90a5c9
        /* Initial number of connections to remote
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 0)
Packit 90a5c9
            return "Min must be a positive number";
Packit 90a5c9
        worker->s->min = ival;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "max")) {
Packit 90a5c9
        /* Maximum number of connections to remote
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 0)
Packit 90a5c9
            return "Max must be a positive number";
Packit 90a5c9
        worker->s->hmax = ival;
Packit 90a5c9
    }
Packit 90a5c9
    /* XXX: More inteligent naming needed */
Packit 90a5c9
    else if (!strcasecmp(key, "smax")) {
Packit 90a5c9
        /* Maximum number of connections to remote that
Packit 90a5c9
         * will not be destroyed
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 0)
Packit 90a5c9
            return "Smax must be a positive number";
Packit 90a5c9
        worker->s->smax = ival;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "acquire")) {
Packit 90a5c9
        /* Acquire timeout in given unit (default is milliseconds).
Packit 90a5c9
         * If set this will be the maximum time to
Packit 90a5c9
         * wait for a free connection.
Packit 90a5c9
         */
Packit 90a5c9
        if (ap_timeout_parameter_parse(val, &timeout, "ms") != APR_SUCCESS)
Packit 90a5c9
            return "Acquire timeout has wrong format";
Packit 90a5c9
        if (timeout < 1000)
Packit 90a5c9
            return "Acquire must be at least one millisecond";
Packit 90a5c9
        worker->s->acquire = timeout;
Packit 90a5c9
        worker->s->acquire_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "timeout")) {
Packit 90a5c9
        /* Connection timeout in seconds.
Packit 90a5c9
         * Defaults to server timeout.
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 1)
Packit 90a5c9
            return "Timeout must be at least one second";
Packit 90a5c9
        worker->s->timeout = apr_time_from_sec(ival);
Packit 90a5c9
        worker->s->timeout_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "iobuffersize")) {
Packit 90a5c9
        long s = atol(val);
Packit 90a5c9
        if (s < 512 && s) {
Packit 90a5c9
            return "IOBufferSize must be >= 512 bytes, or 0 for system default.";
Packit 90a5c9
        }
Packit 90a5c9
        worker->s->io_buffer_size = (s ? s : AP_IOBUFSIZE);
Packit 90a5c9
        worker->s->io_buffer_size_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "receivebuffersize")) {
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 512 && ival != 0) {
Packit 90a5c9
            return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
Packit 90a5c9
        }
Packit 90a5c9
        worker->s->recv_buffer_size = ival;
Packit 90a5c9
        worker->s->recv_buffer_size_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "keepalive")) {
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            worker->s->keepalive = 1;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            worker->s->keepalive = 0;
Packit 90a5c9
        else
Packit 90a5c9
            return "KeepAlive must be On|Off";
Packit 90a5c9
        worker->s->keepalive_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "disablereuse")) {
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            worker->s->disablereuse = 1;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            worker->s->disablereuse = 0;
Packit 90a5c9
        else
Packit 90a5c9
            return "DisableReuse must be On|Off";
Packit 90a5c9
        worker->s->disablereuse_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "enablereuse")) {
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            worker->s->disablereuse = 0;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            worker->s->disablereuse = 1;
Packit 90a5c9
        else
Packit 90a5c9
            return "EnableReuse must be On|Off";
Packit 90a5c9
        worker->s->disablereuse_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "route")) {
Packit 90a5c9
        /* Worker route.
Packit 90a5c9
         */
Packit 90a5c9
        if (strlen(val) >= sizeof(worker->s->route))
Packit 90a5c9
            return apr_psprintf(p, "Route length must be < %d characters",
Packit 90a5c9
                    (int)sizeof(worker->s->route));
Packit 90a5c9
        PROXY_STRNCPY(worker->s->route, val);
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "redirect")) {
Packit 90a5c9
        /* Worker redirection route.
Packit 90a5c9
         */
Packit 90a5c9
        if (strlen(val) >= sizeof(worker->s->redirect))
Packit 90a5c9
            return apr_psprintf(p, "Redirect length must be < %d characters",
Packit 90a5c9
                    (int)sizeof(worker->s->redirect));
Packit 90a5c9
        PROXY_STRNCPY(worker->s->redirect, val);
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "status")) {
Packit 90a5c9
        const char *v;
Packit 90a5c9
        int mode = 1;
Packit 90a5c9
        apr_status_t rv;
Packit 90a5c9
        /* Worker status.
Packit 90a5c9
         */
Packit 90a5c9
        for (v = val; *v; v++) {
Packit 90a5c9
            if (*v == '+') {
Packit 90a5c9
                mode = 1;
Packit 90a5c9
                v++;
Packit 90a5c9
            }
Packit 90a5c9
            else if (*v == '-') {
Packit 90a5c9
                mode = 0;
Packit 90a5c9
                v++;
Packit 90a5c9
            }
Packit 90a5c9
            rv = ap_proxy_set_wstatus(*v, mode, worker);
Packit 90a5c9
            if (rv != APR_SUCCESS)
Packit 90a5c9
                return "Unknown status parameter option";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "flushpackets")) {
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            worker->s->flush_packets = flush_on;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            worker->s->flush_packets = flush_off;
Packit 90a5c9
        else if (!strcasecmp(val, "auto"))
Packit 90a5c9
            worker->s->flush_packets = flush_auto;
Packit 90a5c9
        else
Packit 90a5c9
            return "flushpackets must be on|off|auto";
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "flushwait")) {
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival > 1000 || ival < 0) {
Packit 90a5c9
            return "flushwait must be <= 1000, or 0 for system default of 10 millseconds.";
Packit 90a5c9
        }
Packit 90a5c9
        if (ival == 0)
Packit 90a5c9
            worker->s->flush_wait = PROXY_FLUSH_WAIT;
Packit 90a5c9
        else
Packit 90a5c9
            worker->s->flush_wait = ival * 1000;    /* change to microseconds */
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "ping")) {
Packit 90a5c9
        /* Ping/Pong timeout in given unit (default is second).
Packit 90a5c9
         */
Packit 90a5c9
        if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS)
Packit 90a5c9
            return "Ping/Pong timeout has wrong format";
Packit 90a5c9
        if (timeout < 1000)
Packit 90a5c9
            return "Ping/Pong timeout must be at least one millisecond";
Packit 90a5c9
        worker->s->ping_timeout = timeout;
Packit 90a5c9
        worker->s->ping_timeout_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "lbset")) {
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 0 || ival > 99)
Packit 90a5c9
            return "lbset must be between 0 and 99";
Packit 90a5c9
        worker->s->lbset = ival;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "connectiontimeout")) {
Packit 90a5c9
        /* Request timeout in given unit (default is second).
Packit 90a5c9
         * Defaults to connection timeout
Packit 90a5c9
         */
Packit 90a5c9
        if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS)
Packit 90a5c9
            return "Connectiontimeout has wrong format";
Packit 90a5c9
        if (timeout < 1000)
Packit 90a5c9
            return "Connectiontimeout must be at least one millisecond.";
Packit 90a5c9
        worker->s->conn_timeout = timeout;
Packit 90a5c9
        worker->s->conn_timeout_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "flusher")) {
Packit 90a5c9
        if (strlen(val) >= sizeof(worker->s->flusher))
Packit 90a5c9
            apr_psprintf(p, "flusher name length must be < %d characters",
Packit 90a5c9
                    (int)sizeof(worker->s->flusher));
Packit 90a5c9
        PROXY_STRNCPY(worker->s->flusher, val);
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "upgrade")) {
Packit 90a5c9
        if (PROXY_STRNCPY(worker->s->upgrade, val) != APR_SUCCESS) {
Packit 90a5c9
            return apr_psprintf(p, "upgrade protocol length must be < %d characters",
Packit 90a5c9
                                (int)sizeof(worker->s->upgrade));
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "responsefieldsize")) {
Packit 90a5c9
        long s = atol(val);
Packit 90a5c9
        if (s < 0) {
Packit 90a5c9
            return "ResponseFieldSize must be greater than 0 bytes, or 0 for system default.";
Packit 90a5c9
        }
Packit 90a5c9
        worker->s->response_field_size = (s ? s : HUGE_STRING_LEN);
Packit 90a5c9
        worker->s->response_field_size_set = 1;
Packit 90a5c9
    }
Packit 0d3a01
    else if (!strcasecmp(key, "secret")) {
Packit 0d3a01
        if (PROXY_STRNCPY(worker->s->secret, val) != APR_SUCCESS) {
Packit 0d3a01
            return apr_psprintf(p, "Secret length must be < %d characters",
Packit 0d3a01
                                (int)sizeof(worker->s->secret));
Packit 0d3a01
        }
Packit 0d3a01
    }
Packit 90a5c9
    else {
Packit 90a5c9
        if (set_worker_hc_param_f) {
Packit 90a5c9
            return set_worker_hc_param_f(p, s, worker, key, val, NULL);
Packit 90a5c9
        } else {
Packit 90a5c9
            return "unknown Worker parameter";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *set_balancer_param(proxy_server_conf *conf,
Packit 90a5c9
                                      apr_pool_t *p,
Packit 90a5c9
                                      proxy_balancer *balancer,
Packit 90a5c9
                                      const char *key,
Packit 90a5c9
                                      const char *val)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    int ival;
Packit 90a5c9
    if (!strcasecmp(key, "stickysession")) {
Packit 90a5c9
        char *path;
Packit 90a5c9
        /* Balancer sticky session name.
Packit 90a5c9
         * Set to something like JSESSIONID or
Packit 90a5c9
         * PHPSESSIONID, etc..,
Packit 90a5c9
         */
Packit 90a5c9
        if (strlen(val) >= sizeof(balancer->s->sticky_path))
Packit 90a5c9
            apr_psprintf(p, "stickysession length must be < %d characters",
Packit 90a5c9
                    (int)sizeof(balancer->s->sticky_path));
Packit 90a5c9
        PROXY_STRNCPY(balancer->s->sticky_path, val);
Packit 90a5c9
        PROXY_STRNCPY(balancer->s->sticky, val);
Packit 90a5c9
Packit 90a5c9
        if ((path = strchr((char *)balancer->s->sticky, '|'))) {
Packit 90a5c9
            *path++ = '\0';
Packit 90a5c9
            PROXY_STRNCPY(balancer->s->sticky_path, path);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "stickysessionsep")) {
Packit 90a5c9
        /* separator/delimiter for sessionid and route,
Packit 90a5c9
         * normally '.'
Packit 90a5c9
         */
Packit 90a5c9
        if (strlen(val) != 1) {
Packit 90a5c9
            if (!strcasecmp(val, "off"))
Packit 90a5c9
                balancer->s->sticky_separator = 0;
Packit 90a5c9
            else      
Packit 90a5c9
                return "stickysessionsep must be a single character or Off";
Packit 90a5c9
        }
Packit 90a5c9
        else
Packit 90a5c9
            balancer->s->sticky_separator = *val;
Packit 90a5c9
        balancer->s->sticky_separator_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "nofailover")) {
Packit 90a5c9
        /* If set to 'on' the session will break
Packit 90a5c9
         * if the worker is in error state or
Packit 90a5c9
         * disabled.
Packit 90a5c9
         */
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            balancer->s->sticky_force = 1;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            balancer->s->sticky_force = 0;
Packit 90a5c9
        else
Packit 90a5c9
            return "failover must be On|Off";
Packit 90a5c9
        balancer->s->sticky_force_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "timeout")) {
Packit 90a5c9
        /* Balancer timeout in seconds.
Packit 90a5c9
         * If set this will be the maximum time to
Packit 90a5c9
         * wait for a free worker.
Packit 90a5c9
         * Default is not to wait.
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 1)
Packit 90a5c9
            return "timeout must be at least one second";
Packit 90a5c9
        balancer->s->timeout = apr_time_from_sec(ival);
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "maxattempts")) {
Packit 90a5c9
        /* Maximum number of failover attempts before
Packit 90a5c9
         * giving up.
Packit 90a5c9
         */
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 0)
Packit 90a5c9
            return "maximum number of attempts must be a positive number";
Packit 90a5c9
        balancer->s->max_attempts = ival;
Packit 90a5c9
        balancer->s->max_attempts_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "lbmethod")) {
Packit 90a5c9
        proxy_balancer_method *provider;
Packit 90a5c9
        if (strlen(val) > (sizeof(balancer->s->lbpname)-1))
Packit 90a5c9
            return "unknown lbmethod";
Packit 90a5c9
        provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0");
Packit 90a5c9
        if (provider) {
Packit 90a5c9
            balancer->lbmethod = provider;
Packit 90a5c9
            if (PROXY_STRNCPY(balancer->s->lbpname, val) == APR_SUCCESS) {
Packit 90a5c9
                balancer->lbmethod_set = 1;
Packit 90a5c9
                return NULL;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                return "lbmethod name too large";
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        return "unknown lbmethod";
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "scolonpathdelim")) {
Packit 90a5c9
        /* If set to 'on' then ';' will also be
Packit 90a5c9
         * used as a session path separator/delim (ala
Packit 90a5c9
         * mod_jk)
Packit 90a5c9
         */
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            balancer->s->scolonsep = 1;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            balancer->s->scolonsep = 0;
Packit 90a5c9
        else
Packit 90a5c9
            return "scolonpathdelim must be On|Off";
Packit 90a5c9
        balancer->s->scolonsep_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "failonstatus")) {
Packit 90a5c9
        char *val_split;
Packit 90a5c9
        char *status;
Packit 90a5c9
        char *tok_state;
Packit 90a5c9
Packit 90a5c9
        val_split = apr_pstrdup(p, val);
Packit 90a5c9
Packit 90a5c9
        balancer->errstatuses = apr_array_make(p, 1, sizeof(int));
Packit 90a5c9
Packit 90a5c9
        status = apr_strtok(val_split, ", ", &tok_state);
Packit 90a5c9
        while (status != NULL) {
Packit 90a5c9
            ival = atoi(status);
Packit 90a5c9
            if (ap_is_HTTP_VALID_RESPONSE(ival)) {
Packit 90a5c9
                *(int *)apr_array_push(balancer->errstatuses) = ival;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                return "failonstatus must be one or more HTTP response codes";
Packit 90a5c9
            }
Packit 90a5c9
            status = apr_strtok(NULL, ", ", &tok_state);
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "failontimeout")) {
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            balancer->failontimeout = 1;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            balancer->failontimeout = 0;
Packit 90a5c9
        else
Packit 90a5c9
            return "failontimeout must be On|Off";
Packit 90a5c9
        balancer->failontimeout_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "nonce")) {
Packit 90a5c9
        if (!strcasecmp(val, "None")) {
Packit 90a5c9
            *balancer->s->nonce = '\0';
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            if (PROXY_STRNCPY(balancer->s->nonce, val) != APR_SUCCESS) {
Packit 90a5c9
                return "Provided nonce is too large";
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        balancer->s->nonce_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "growth")) {
Packit 90a5c9
        ival = atoi(val);
Packit 90a5c9
        if (ival < 1 || ival > 100)   /* arbitrary limit here */
Packit 90a5c9
            return "growth must be between 1 and 100";
Packit 90a5c9
        balancer->growth = ival;
Packit 90a5c9
        balancer->growth_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else if (!strcasecmp(key, "forcerecovery")) {
Packit 90a5c9
        if (!strcasecmp(val, "on"))
Packit 90a5c9
            balancer->s->forcerecovery = 1;
Packit 90a5c9
        else if (!strcasecmp(val, "off"))
Packit 90a5c9
            balancer->s->forcerecovery = 0;
Packit 90a5c9
        else
Packit 90a5c9
            return "forcerecovery must be On|Off";
Packit 90a5c9
        balancer->s->forcerecovery_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return "unknown Balancer parameter";
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int alias_match(const char *uri, const char *alias_fakename)
Packit 90a5c9
{
Packit 90a5c9
    const char *end_fakename = alias_fakename + strlen(alias_fakename);
Packit 90a5c9
    const char *aliasp = alias_fakename, *urip = uri;
Packit 90a5c9
    const char *end_uri = uri + strlen(uri);
Packit 90a5c9
Packit 90a5c9
    while (aliasp < end_fakename && urip < end_uri) {
Packit 90a5c9
        if (*aliasp == '/') {
Packit 90a5c9
            /* any number of '/' in the alias matches any number in
Packit 90a5c9
             * the supplied URI, but there must be at least one...
Packit 90a5c9
             */
Packit 90a5c9
            if (*urip != '/')
Packit 90a5c9
                return 0;
Packit 90a5c9
Packit 90a5c9
            while (*aliasp == '/')
Packit 90a5c9
                ++aliasp;
Packit 90a5c9
            while (*urip == '/')
Packit 90a5c9
                ++urip;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            /* Other characters are compared literally */
Packit 90a5c9
            if (*urip++ != *aliasp++)
Packit 90a5c9
                return 0;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* fixup badly encoded stuff (e.g. % as last character) */
Packit 90a5c9
    if (aliasp > end_fakename) {
Packit 90a5c9
        aliasp = end_fakename;
Packit 90a5c9
    }
Packit 90a5c9
    if (urip > end_uri) {
Packit 90a5c9
        urip = end_uri;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
   /* We reach the end of the uri before the end of "alias_fakename"
Packit 90a5c9
    * for example uri is "/" and alias_fakename "/examples"
Packit 90a5c9
    */
Packit 90a5c9
   if (urip == end_uri && aliasp != end_fakename) {
Packit 90a5c9
       return 0;
Packit 90a5c9
   }
Packit 90a5c9
Packit 90a5c9
    /* Check last alias path component matched all the way */
Packit 90a5c9
    if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
Packit 90a5c9
        return 0;
Packit 90a5c9
Packit 90a5c9
    /* Return number of characters from URI which matched (may be
Packit 90a5c9
     * greater than length of alias, since we may have matched
Packit 90a5c9
     * doubled slashes)
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    return urip - uri;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Detect if an absoluteURI should be proxied or not.  Note that we
Packit 90a5c9
 * have to do this during this phase because later phases are
Packit 90a5c9
 * "short-circuiting"... i.e. translate_names will end when the first
Packit 90a5c9
 * module returns OK.  So for example, if the request is something like:
Packit 90a5c9
 *
Packit 90a5c9
 * GET http://othervhost/cgi-bin/printenv HTTP/1.0
Packit 90a5c9
 *
Packit 90a5c9
 * mod_alias will notice the /cgi-bin part and ScriptAlias it and
Packit 90a5c9
 * short-circuit the proxy... just because of the ordering in the
Packit 90a5c9
 * configuration file.
Packit 90a5c9
 */
Packit 90a5c9
static int proxy_detect(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    void *sconf = r->server->module_config;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
        (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    /* Ick... msvc (perhaps others) promotes ternary short results to int */
Packit 90a5c9
Packit 90a5c9
    if (conf->req && r->parsed_uri.scheme) {
Packit 90a5c9
        /* but it might be something vhosted */
Packit 90a5c9
        if (!(r->parsed_uri.hostname
Packit 90a5c9
              && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r))
Packit 90a5c9
              && ap_matches_request_vhost(r, r->parsed_uri.hostname,
Packit 90a5c9
                                          (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
Packit 90a5c9
                                                       : ap_default_port(r))))) {
Packit 90a5c9
            r->proxyreq = PROXYREQ_PROXY;
Packit 90a5c9
            r->uri = r->unparsed_uri;
Packit 90a5c9
            r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
Packit 90a5c9
            r->handler = "proxy-server";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    /* We need special treatment for CONNECT proxying: it has no scheme part */
Packit 90a5c9
    else if (conf->req && r->method_number == M_CONNECT
Packit 90a5c9
             && r->parsed_uri.hostname
Packit 90a5c9
             && r->parsed_uri.port_str) {
Packit 90a5c9
        r->proxyreq = PROXYREQ_PROXY;
Packit 90a5c9
        r->uri = r->unparsed_uri;
Packit 90a5c9
        r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
Packit 90a5c9
        r->handler = "proxy-server";
Packit 90a5c9
    }
Packit 90a5c9
    return DECLINED;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *proxy_interpolate(request_rec *r, const char *str)
Packit 90a5c9
{
Packit 90a5c9
    /* Interpolate an env str in a configuration string
Packit 90a5c9
     * Syntax ${var} --> value_of(var)
Packit 90a5c9
     * Method: replace one var, and recurse on remainder of string
Packit 90a5c9
     * Nothing clever here, and crap like nested vars may do silly things
Packit 90a5c9
     * but we'll at least avoid sending the unwary into a loop
Packit 90a5c9
     */
Packit 90a5c9
    const char *start;
Packit 90a5c9
    const char *end;
Packit 90a5c9
    const char *var;
Packit 90a5c9
    const char *val;
Packit 90a5c9
    const char *firstpart;
Packit 90a5c9
Packit 90a5c9
    start = ap_strstr_c(str, "${");
Packit 90a5c9
    if (start == NULL) {
Packit 90a5c9
        return str;
Packit 90a5c9
    }
Packit 90a5c9
    end = ap_strchr_c(start+2, '}');
Packit 90a5c9
    if (end == NULL) {
Packit 90a5c9
        return str;
Packit 90a5c9
    }
Packit 90a5c9
    /* OK, this is syntax we want to interpolate.  Is there such a var ? */
Packit 90a5c9
    var = apr_pstrmemdup(r->pool, start+2, end-(start+2));
Packit 90a5c9
    val = apr_table_get(r->subprocess_env, var);
Packit 90a5c9
    firstpart = apr_pstrmemdup(r->pool, str, (start-str));
Packit 90a5c9
Packit 90a5c9
    if (val == NULL) {
Packit 90a5c9
        return apr_pstrcat(r->pool, firstpart,
Packit 90a5c9
                           proxy_interpolate(r, end+1), NULL);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return apr_pstrcat(r->pool, firstpart, val,
Packit 90a5c9
                           proxy_interpolate(r, end+1), NULL);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
static apr_array_header_t *proxy_vars(request_rec *r,
Packit 90a5c9
                                      apr_array_header_t *hdr)
Packit 90a5c9
{
Packit 90a5c9
    int i;
Packit 90a5c9
    apr_array_header_t *ret = apr_array_make(r->pool, hdr->nelts,
Packit 90a5c9
                                             sizeof (struct proxy_alias));
Packit 90a5c9
    struct proxy_alias *old = (struct proxy_alias *) hdr->elts;
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < hdr->nelts; ++i) {
Packit 90a5c9
        struct proxy_alias *newcopy = apr_array_push(ret);
Packit 90a5c9
        newcopy->fake = (old[i].flags & PROXYPASS_INTERPOLATE)
Packit 90a5c9
                        ? proxy_interpolate(r, old[i].fake) : old[i].fake;
Packit 90a5c9
        newcopy->real = (old[i].flags & PROXYPASS_INTERPOLATE)
Packit 90a5c9
                        ? proxy_interpolate(r, old[i].real) : old[i].real;
Packit 90a5c9
    }
Packit 90a5c9
    return ret;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r, struct proxy_alias *ent,
Packit 90a5c9
                                        proxy_dir_conf *dconf)
Packit 90a5c9
{
Packit 90a5c9
    int len;
Packit 90a5c9
    const char *fake;
Packit 90a5c9
    const char *real;
Packit 90a5c9
    ap_regmatch_t regm[AP_MAX_REG_MATCH];
Packit 90a5c9
    ap_regmatch_t reg1[AP_MAX_REG_MATCH];
Packit 90a5c9
    char *found = NULL;
Packit 90a5c9
    int mismatch = 0;
Packit 90a5c9
    unsigned int nocanon = ent->flags & PROXYPASS_NOCANON;
Packit 90a5c9
    const char *use_uri = nocanon ? r->unparsed_uri : r->uri;
Packit 90a5c9
Packit 90a5c9
    if (dconf && (dconf->interpolate_env == 1) && (ent->flags & PROXYPASS_INTERPOLATE)) {
Packit 90a5c9
        fake = proxy_interpolate(r, ent->fake);
Packit 90a5c9
        real = proxy_interpolate(r, ent->real);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        fake = ent->fake;
Packit 90a5c9
        real = ent->real;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(03461)
Packit 90a5c9
                  "attempting to match URI path '%s' against %s '%s' for "
Packit 90a5c9
                  "proxying", r->uri, (ent->regex ? "pattern" : "prefix"),
Packit 90a5c9
                  fake);
Packit 90a5c9
Packit 90a5c9
    if (ent->regex) {
Packit 90a5c9
        if (!ap_regexec(ent->regex, r->uri, AP_MAX_REG_MATCH, regm, 0)) {
Packit 90a5c9
            if ((real[0] == '!') && (real[1] == '\0')) {
Packit 90a5c9
                ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03462)
Packit 90a5c9
                              "proxying is explicitly disabled for URI path "
Packit 90a5c9
                              "'%s'; declining", r->uri);
Packit 90a5c9
                return DECLINED;
Packit 90a5c9
            }
Packit 90a5c9
            /* test that we haven't reduced the URI */
Packit 90a5c9
            if (nocanon && ap_regexec(ent->regex, r->unparsed_uri,
Packit 90a5c9
                    AP_MAX_REG_MATCH, reg1, 0)) {
Packit 90a5c9
                mismatch = 1;
Packit 90a5c9
                use_uri = r->uri;
Packit 90a5c9
            }
Packit 90a5c9
            found = ap_pregsub(r->pool, real, use_uri, AP_MAX_REG_MATCH,
Packit 90a5c9
                    (use_uri == r->uri) ? regm : reg1);
Packit 90a5c9
            if (!found) {
Packit 90a5c9
                ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01135)
Packit 90a5c9
                              "Substitution in regular expression failed. "
Packit 90a5c9
                              "Replacement too long?");
Packit 90a5c9
                return HTTP_INTERNAL_SERVER_ERROR;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            /* Note: The strcmp() below catches cases where there
Packit 90a5c9
             * was no regex substitution. This is so cases like:
Packit 90a5c9
             *
Packit 90a5c9
             *    ProxyPassMatch \.gif balancer://foo
Packit 90a5c9
             *
Packit 90a5c9
             * will work "as expected". The upshot is that the 2
Packit 90a5c9
             * directives below act the exact same way (ie: $1 is implied):
Packit 90a5c9
             *
Packit 90a5c9
             *    ProxyPassMatch ^(/.*\.gif)$ balancer://foo
Packit 90a5c9
             *    ProxyPassMatch ^(/.*\.gif)$ balancer://foo$1
Packit 90a5c9
             *
Packit 90a5c9
             * which may be confusing.
Packit 90a5c9
             */
Packit 90a5c9
            if (strcmp(found, real) != 0) {
Packit 90a5c9
                found = apr_pstrcat(r->pool, "proxy:", found, NULL);
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                found = apr_pstrcat(r->pool, "proxy:", real, use_uri, NULL);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        len = alias_match(r->uri, fake);
Packit 90a5c9
Packit 90a5c9
        if (len != 0) {
Packit 90a5c9
            if ((real[0] == '!') && (real[1] == '\0')) {
Packit 90a5c9
                ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03463)
Packit 90a5c9
                              "proxying is explicitly disabled for URI path "
Packit 90a5c9
                              "'%s'; declining", r->uri);
Packit 90a5c9
                return DECLINED;
Packit 90a5c9
            }
Packit 90a5c9
            if (nocanon && len != alias_match(r->unparsed_uri, ent->fake)) {
Packit 90a5c9
                mismatch = 1;
Packit 90a5c9
                use_uri = r->uri;
Packit 90a5c9
            }
Packit 90a5c9
            found = apr_pstrcat(r->pool, "proxy:", real, use_uri + len, NULL);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    if (mismatch) {
Packit 90a5c9
        /* We made a reducing transformation, so we can't safely use
Packit 90a5c9
         * unparsed_uri.  Safe fallback is to ignore nocanon.
Packit 90a5c9
         */
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01136)
Packit 90a5c9
                "Unescaped URL path matched ProxyPass; ignoring unsafe nocanon");
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (found) {
Packit 90a5c9
        r->filename = found;
Packit 90a5c9
        r->handler = "proxy-server";
Packit 90a5c9
        r->proxyreq = PROXYREQ_REVERSE;
Packit 90a5c9
        if (nocanon && !mismatch) {
Packit 90a5c9
            /* mod_proxy_http needs to be told.  Different module. */
Packit 90a5c9
            apr_table_setn(r->notes, "proxy-nocanon", "1");
Packit 90a5c9
        }
Packit 90a5c9
        if (ent->flags & PROXYPASS_NOQUERY) {
Packit 90a5c9
            apr_table_setn(r->notes, "proxy-noquery", "1");
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(03464)
Packit 90a5c9
                      "URI path '%s' matches proxy handler '%s'", r->uri,
Packit 90a5c9
                      found);
Packit 90a5c9
Packit 90a5c9
        return OK;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return DONE;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int proxy_trans(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    int i;
Packit 90a5c9
    struct proxy_alias *ent;
Packit 90a5c9
    proxy_dir_conf *dconf;
Packit 90a5c9
    proxy_server_conf *conf;
Packit 90a5c9
Packit 90a5c9
    if (r->proxyreq) {
Packit 90a5c9
        /* someone has already set up the proxy, it was possibly ourselves
Packit 90a5c9
         * in proxy_detect
Packit 90a5c9
         */
Packit 90a5c9
        return OK;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if ((r->unparsed_uri[0] == '*' && r->unparsed_uri[1] == '\0')
Packit 90a5c9
        || !r->uri || r->uri[0] != '/') {
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
    }
Packit 90a5c9
   
Packit 90a5c9
    if (apr_table_get(r->subprocess_env, "no-proxy")) { 
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* XXX: since r->uri has been manipulated already we're not really
Packit 90a5c9
     * compliant with RFC1945 at this point.  But this probably isn't
Packit 90a5c9
     * an issue because this is a hybrid proxy/origin server.
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    /* short way - this location is reverse proxied? */
Packit 90a5c9
    if (dconf->alias) {
Packit 90a5c9
        int rv = ap_proxy_trans_match(r, dconf->alias, dconf);
Packit 90a5c9
        if (DONE != rv) {
Packit 90a5c9
            return rv;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    conf = (proxy_server_conf *) ap_get_module_config(r->server->module_config,
Packit 90a5c9
                                                      &proxy_module);
Packit 90a5c9
Packit 90a5c9
    /* long way - walk the list of aliases, find a match */
Packit 90a5c9
    if (conf->aliases->nelts) {
Packit 90a5c9
        ent = (struct proxy_alias *) conf->aliases->elts;
Packit 90a5c9
        for (i = 0; i < conf->aliases->nelts; i++) {
Packit 90a5c9
            int rv = ap_proxy_trans_match(r, &ent[i], dconf);
Packit 90a5c9
            if (DONE != rv) {
Packit 90a5c9
                return rv;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return DECLINED;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int proxy_walk(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,
Packit 90a5c9
                                                    &proxy_module);
Packit 90a5c9
    ap_conf_vector_t *per_dir_defaults = r->per_dir_config;
Packit 90a5c9
    ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts;
Packit 90a5c9
    ap_conf_vector_t *entry_config;
Packit 90a5c9
    proxy_dir_conf *entry_proxy;
Packit 90a5c9
    int num_sec = sconf->sec_proxy->nelts;
Packit 90a5c9
    /* XXX: shouldn't we use URI here?  Canonicalize it first?
Packit 90a5c9
     * Pass over "proxy:" prefix
Packit 90a5c9
     */
Packit 90a5c9
    const char *proxyname = r->filename + 6;
Packit 90a5c9
    int j;
Packit 90a5c9
    apr_pool_t *rxpool = NULL;
Packit 90a5c9
Packit 90a5c9
    for (j = 0; j < num_sec; ++j)
Packit 90a5c9
    {
Packit 90a5c9
        int nmatch = 0;
Packit 90a5c9
        int i;
Packit 90a5c9
        ap_regmatch_t *pmatch = NULL;
Packit 90a5c9
Packit 90a5c9
        entry_config = sec_proxy[j];
Packit 90a5c9
        entry_proxy = ap_get_module_config(entry_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
        if (entry_proxy->r) {
Packit 90a5c9
Packit 90a5c9
            if (entry_proxy->refs && entry_proxy->refs->nelts) {
Packit 90a5c9
                if (!rxpool) {
Packit 90a5c9
                    apr_pool_create(&rxpool, r->pool);
Packit 90a5c9
                }
Packit 90a5c9
                nmatch = entry_proxy->refs->nelts;
Packit 90a5c9
                pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            if (ap_regexec(entry_proxy->r, proxyname, nmatch, pmatch, 0)) {
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            for (i = 0; i < nmatch; i++) {
Packit 90a5c9
                if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 &&
Packit 90a5c9
                        ((const char **)entry_proxy->refs->elts)[i]) {
Packit 90a5c9
                    apr_table_setn(r->subprocess_env,
Packit 90a5c9
                            ((const char **)entry_proxy->refs->elts)[i],
Packit 90a5c9
                            apr_pstrndup(r->pool,
Packit 90a5c9
                                    proxyname + pmatch[i].rm_so,
Packit 90a5c9
                                    pmatch[i].rm_eo - pmatch[i].rm_so));
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        else if (
Packit 90a5c9
            /* XXX: What about case insensitive matching ???
Packit 90a5c9
             * Compare regex, fnmatch or string as appropriate
Packit 90a5c9
             * If the entry doesn't relate, then continue
Packit 90a5c9
             */
Packit 90a5c9
            entry_proxy->p_is_fnmatch ? apr_fnmatch(entry_proxy->p,
Packit 90a5c9
                    proxyname, 0) :
Packit 90a5c9
                    strncmp(proxyname, entry_proxy->p,
Packit 90a5c9
                            strlen(entry_proxy->p))) {
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
        per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,
Packit 90a5c9
                                                             entry_config);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    r->per_dir_config = per_dir_defaults;
Packit 90a5c9
Packit 90a5c9
    if (rxpool) {
Packit 90a5c9
        apr_pool_destroy(rxpool);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int proxy_map_location(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    int access_status;
Packit 90a5c9
Packit 90a5c9
    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
Packit 90a5c9
    /* Don't let the core or mod_http map_to_storage hooks handle this,
Packit 90a5c9
     * We don't need directory/file_walk, and we want to TRACE on our own.
Packit 90a5c9
     */
Packit 90a5c9
    if ((access_status = proxy_walk(r))) {
Packit 90a5c9
        ap_die(access_status, r);
Packit 90a5c9
        return access_status;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* -------------------------------------------------------------- */
Packit 90a5c9
/* Fixup the filename */
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Canonicalise the URL
Packit 90a5c9
 */
Packit 90a5c9
static int proxy_fixup(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    char *url, *p;
Packit 90a5c9
    int access_status;
Packit 90a5c9
    proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config,
Packit 90a5c9
                                                 &proxy_module);
Packit 90a5c9
Packit 90a5c9
    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
Packit 90a5c9
    /* XXX: Shouldn't we try this before we run the proxy_walk? */
Packit 90a5c9
    url = &r->filename[6];
Packit 90a5c9
Packit 90a5c9
    if ((dconf->interpolate_env == 1) && (r->proxyreq == PROXYREQ_REVERSE)) {
Packit 90a5c9
        /* create per-request copy of reverse proxy conf,
Packit 90a5c9
         * and interpolate vars in it
Packit 90a5c9
         */
Packit 90a5c9
        proxy_req_conf *rconf = apr_palloc(r->pool, sizeof(proxy_req_conf));
Packit 90a5c9
        ap_set_module_config(r->request_config, &proxy_module, rconf);
Packit 90a5c9
        rconf->raliases = proxy_vars(r, dconf->raliases);
Packit 90a5c9
        rconf->cookie_paths = proxy_vars(r, dconf->cookie_paths);
Packit 90a5c9
        rconf->cookie_domains = proxy_vars(r, dconf->cookie_domains);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* canonicalise each specific scheme */
Packit 90a5c9
    if ((access_status = proxy_run_canon_handler(r, url))) {
Packit 90a5c9
        return access_status;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    p = strchr(url, ':');
Packit 90a5c9
    if (p == NULL || p == url)
Packit 90a5c9
        return HTTP_BAD_REQUEST;
Packit 90a5c9
Packit 90a5c9
    return OK;      /* otherwise; we've done the best we can */
Packit 90a5c9
}
Packit 90a5c9
/* Send a redirection if the request contains a hostname which is not */
Packit 90a5c9
/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
Packit 90a5c9
/* servers like Netscape's allow this and access hosts from the local */
Packit 90a5c9
/* domain in this case. I think it is better to redirect to a FQDN, since */
Packit 90a5c9
/* these will later be found in the bookmarks files. */
Packit 90a5c9
/* The "ProxyDomain" directive determines what domain will be appended */
Packit 90a5c9
static int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
Packit 90a5c9
{
Packit 90a5c9
    char *nuri;
Packit 90a5c9
    const char *ref;
Packit 90a5c9
Packit 90a5c9
    /* We only want to worry about GETs */
Packit 90a5c9
    if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
Packit 90a5c9
    /* If host does contain a dot already, or it is "localhost", decline */
Packit 90a5c9
    if (strchr(r->parsed_uri.hostname, '.') != NULL /* has domain, or IPv4 literal */
Packit 90a5c9
     || strchr(r->parsed_uri.hostname, ':') != NULL /* IPv6 literal */
Packit 90a5c9
     || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
Packit 90a5c9
        return DECLINED;    /* host name has a dot already */
Packit 90a5c9
Packit 90a5c9
    ref = apr_table_get(r->headers_in, "Referer");
Packit 90a5c9
Packit 90a5c9
    /* Reassemble the request, but insert the domain after the host name */
Packit 90a5c9
    /* Note that the domain name always starts with a dot */
Packit 90a5c9
    r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname,
Packit 90a5c9
                                         domain, NULL);
Packit 90a5c9
    nuri = apr_uri_unparse(r->pool,
Packit 90a5c9
                           &r->parsed_uri,
Packit 90a5c9
                           APR_URI_UNP_REVEALPASSWORD);
Packit 90a5c9
Packit 90a5c9
    apr_table_setn(r->headers_out, "Location", nuri);
Packit 90a5c9
    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01138)
Packit 90a5c9
                  "Domain missing: %s sent to %s%s%s", r->uri,
Packit 90a5c9
                  apr_uri_unparse(r->pool, &r->parsed_uri,
Packit 90a5c9
                                  APR_URI_UNP_OMITUSERINFO),
Packit 90a5c9
                  ref ? " from " : "", ref ? ref : "");
Packit 90a5c9
Packit 90a5c9
    return HTTP_MOVED_PERMANENTLY;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* -------------------------------------------------------------- */
Packit 90a5c9
/* Invoke handler */
Packit 90a5c9
Packit 90a5c9
static int proxy_handler(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    char *uri, *scheme, *p;
Packit 90a5c9
    const char *p2;
Packit 90a5c9
    void *sconf = r->server->module_config;
Packit 90a5c9
    proxy_server_conf *conf = (proxy_server_conf *)
Packit 90a5c9
        ap_get_module_config(sconf, &proxy_module);
Packit 90a5c9
    apr_array_header_t *proxies = conf->proxies;
Packit 90a5c9
    struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
Packit 90a5c9
    int i, rc, access_status;
Packit 90a5c9
    int direct_connect = 0;
Packit 90a5c9
    const char *str;
Packit 90a5c9
    apr_int64_t maxfwd;
Packit 90a5c9
    proxy_balancer *balancer = NULL;
Packit 90a5c9
    proxy_worker *worker = NULL;
Packit 90a5c9
    int attempts = 0, max_attempts = 0;
Packit 90a5c9
    struct dirconn_entry *list = (struct dirconn_entry *)conf->dirconn->elts;
Packit 90a5c9
    int saved_status;
Packit 90a5c9
Packit 90a5c9
    /* is this for us? */
Packit 90a5c9
    if (!r->filename) {
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!r->proxyreq) {
Packit 90a5c9
        /* We may have forced the proxy handler via config or .htaccess */
Packit 90a5c9
        if (r->handler &&
Packit 90a5c9
            strncmp(r->handler, "proxy:", 6) == 0 &&
Packit 90a5c9
            strncmp(r->filename, "proxy:", 6) != 0) {
Packit 90a5c9
            r->proxyreq = PROXYREQ_REVERSE;
Packit 90a5c9
            r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            return DECLINED;
Packit 90a5c9
        }
Packit 90a5c9
    } else if (strncmp(r->filename, "proxy:", 6) != 0) {
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* handle max-forwards / OPTIONS / TRACE */
Packit 90a5c9
    if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) {
Packit 90a5c9
        char *end;
Packit 90a5c9
        maxfwd = apr_strtoi64(str, &end, 10);
Packit 90a5c9
        if (maxfwd < 0 || maxfwd == APR_INT64_MAX || *end) {
Packit f2471b
            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() 
Packit f2471b
                          "Max-Forwards value '%s' could not be parsed", str);
Packit f2471b
            return ap_proxyerror(r, HTTP_BAD_REQUEST, 
Packit f2471b
                          "Max-Forwards request header could not be parsed");
Packit 90a5c9
        }
Packit 90a5c9
        else if (maxfwd == 0) {
Packit 90a5c9
            switch (r->method_number) {
Packit 90a5c9
            case M_TRACE: {
Packit 90a5c9
                int access_status;
Packit 90a5c9
                r->proxyreq = PROXYREQ_NONE;
Packit 90a5c9
                access_status = ap_send_http_trace(r);
Packit 90a5c9
                ap_die(access_status, r);
Packit 90a5c9
                return OK;
Packit 90a5c9
            }
Packit 90a5c9
            case M_OPTIONS: {
Packit 90a5c9
                int access_status;
Packit 90a5c9
                r->proxyreq = PROXYREQ_NONE;
Packit 90a5c9
                access_status = ap_send_http_options(r);
Packit 90a5c9
                ap_die(access_status, r);
Packit 90a5c9
                return OK;
Packit 90a5c9
            }
Packit 90a5c9
            default: {
Packit 90a5c9
                return ap_proxyerror(r, HTTP_BAD_REQUEST,
Packit 90a5c9
                                     "Max-Forwards has reached zero - proxy loop?");
Packit 90a5c9
            }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        maxfwd = (maxfwd > 0) ? maxfwd - 1 : 0;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        /* set configured max-forwards */
Packit 90a5c9
        maxfwd = conf->maxfwd;
Packit 90a5c9
    }
Packit 90a5c9
    if (maxfwd >= 0) {
Packit 90a5c9
        apr_table_setn(r->headers_in, "Max-Forwards",
Packit 90a5c9
                       apr_psprintf(r->pool, "%" APR_INT64_T_FMT, maxfwd));
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (r->method_number == M_TRACE) {
Packit 90a5c9
        core_server_config *coreconf = (core_server_config *)
Packit 90a5c9
                                       ap_get_core_module_config(sconf);
Packit 90a5c9
Packit 90a5c9
        if (coreconf->trace_enable == AP_TRACE_DISABLE)
Packit 90a5c9
        {
Packit 90a5c9
            /* Allow "error-notes" string to be printed by ap_send_error_response()
Packit 90a5c9
             * Note; this goes nowhere, canned error response need an overhaul.
Packit 90a5c9
             */
Packit 90a5c9
            apr_table_setn(r->notes, "error-notes",
Packit 90a5c9
                           "TRACE forbidden by server configuration");
Packit 90a5c9
            apr_table_setn(r->notes, "verbose-error-to", "*");
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01139)
Packit 90a5c9
                          "TRACE forbidden by server configuration");
Packit 90a5c9
            return HTTP_METHOD_NOT_ALLOWED;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* Can't test ap_should_client_block, we aren't ready to send
Packit 90a5c9
         * the client a 100 Continue response till the connection has
Packit 90a5c9
         * been established
Packit 90a5c9
         */
Packit 90a5c9
        if (coreconf->trace_enable != AP_TRACE_EXTENDED
Packit 90a5c9
            && (r->read_length || r->read_chunked || r->remaining))
Packit 90a5c9
        {
Packit 90a5c9
            /* Allow "error-notes" string to be printed by ap_send_error_response()
Packit 90a5c9
             * Note; this goes nowhere, canned error response need an overhaul.
Packit 90a5c9
             */
Packit 90a5c9
            apr_table_setn(r->notes, "error-notes",
Packit 90a5c9
                           "TRACE with request body is not allowed");
Packit 90a5c9
            apr_table_setn(r->notes, "verbose-error-to", "*");
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01140)
Packit 90a5c9
                          "TRACE with request body is not allowed");
Packit 90a5c9
            return HTTP_REQUEST_ENTITY_TOO_LARGE;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    uri = r->filename + 6;
Packit 90a5c9
    p = strchr(uri, ':');
Packit 90a5c9
    if (p == NULL) {
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01141)
Packit 90a5c9
                      "proxy_handler no URL in %s", r->filename);
Packit 90a5c9
        return HTTP_BAD_REQUEST;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* If the host doesn't have a domain name, add one and redirect. */
Packit 90a5c9
    if (conf->domain != NULL) {
Packit 90a5c9
        rc = proxy_needsdomain(r, uri, conf->domain);
Packit 90a5c9
        if (ap_is_HTTP_REDIRECT(rc))
Packit 90a5c9
            return HTTP_MOVED_PERMANENTLY;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    scheme = apr_pstrmemdup(r->pool, uri, p - uri);
Packit 90a5c9
    /* Check URI's destination host against NoProxy hosts */
Packit 90a5c9
    /* Bypass ProxyRemote server lookup if configured as NoProxy */
Packit 90a5c9
    for (direct_connect = i = 0; i < conf->dirconn->nelts &&
Packit 90a5c9
                                        !direct_connect; i++) {
Packit 90a5c9
        direct_connect = list[i].matcher(&list[i], r);
Packit 90a5c9
    }
Packit 90a5c9
#if DEBUGGING
Packit 90a5c9
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
Packit 90a5c9
                (direct_connect) ? APLOGNO(03231) "NoProxy for %s" : APLOGNO(03232) "UseProxy for %s",
Packit 90a5c9
                r->uri);
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    do {
Packit 90a5c9
        char *url = uri;
Packit 90a5c9
        /* Try to obtain the most suitable worker */
Packit 90a5c9
        access_status = ap_proxy_pre_request(&worker, &balancer, r, conf, &url;;
Packit 90a5c9
        if (access_status != OK) {
Packit 90a5c9
            /*
Packit 90a5c9
             * Only return if access_status is not HTTP_SERVICE_UNAVAILABLE
Packit 90a5c9
             * This gives other modules the chance to hook into the
Packit 90a5c9
             * request_status hook and decide what to do in this situation.
Packit 90a5c9
             */
Packit 90a5c9
            if (access_status != HTTP_SERVICE_UNAVAILABLE)
Packit 90a5c9
                return access_status;
Packit 90a5c9
            /*
Packit 90a5c9
             * Ensure that balancer is NULL if worker is NULL to prevent
Packit 90a5c9
             * potential problems in the post_request hook.
Packit 90a5c9
             */
Packit 90a5c9
            if (!worker)
Packit 90a5c9
                balancer = NULL;
Packit 90a5c9
            goto cleanup;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* Initialise worker if needed, note the shared area must be initialized by the balancer logic */
Packit 90a5c9
        if (balancer) {
Packit 90a5c9
            ap_proxy_initialize_worker(worker, r->server, conf->pool);
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (balancer && balancer->s->max_attempts_set && !max_attempts)
Packit 90a5c9
            max_attempts = balancer->s->max_attempts;
Packit 90a5c9
        /* firstly, try a proxy, unless a NoProxy directive is active */
Packit 90a5c9
        if (!direct_connect) {
Packit 90a5c9
            for (i = 0; i < proxies->nelts; i++) {
Packit 90a5c9
                p2 = ap_strchr_c(ents[i].scheme, ':');  /* is it a partial URL? */
Packit 90a5c9
                if (strcmp(ents[i].scheme, "*") == 0 ||
Packit 90a5c9
                    (ents[i].use_regex &&
Packit 90a5c9
                     ap_regexec(ents[i].regexp, url, 0, NULL, 0) == 0) ||
Packit 90a5c9
                    (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
Packit 90a5c9
                    (p2 != NULL &&
Packit 90a5c9
                    strncasecmp(url, ents[i].scheme,
Packit 90a5c9
                                strlen(ents[i].scheme)) == 0)) {
Packit 90a5c9
Packit 90a5c9
                    /* handle the scheme */
Packit 90a5c9
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142)
Packit 90a5c9
                                  "Trying to run scheme_handler against proxy");
Packit 90a5c9
                    access_status = proxy_run_scheme_handler(r, worker,
Packit 90a5c9
                                                             conf, url,
Packit 90a5c9
                                                             ents[i].hostname,
Packit 90a5c9
                                                             ents[i].port);
Packit 90a5c9
Packit 90a5c9
                    /* Did the scheme handler process the request? */
Packit 90a5c9
                    if (access_status != DECLINED) {
Packit 90a5c9
                        const char *cl_a;
Packit 90a5c9
                        char *end;
Packit 90a5c9
                        apr_off_t cl;
Packit 90a5c9
Packit 90a5c9
                        /*
Packit 90a5c9
                         * An fatal error or success, so no point in
Packit 90a5c9
                         * retrying with a direct connection.
Packit 90a5c9
                         */
Packit 90a5c9
                        if (access_status != HTTP_BAD_GATEWAY) {
Packit 90a5c9
                            goto cleanup;
Packit 90a5c9
                        }
Packit 90a5c9
                        cl_a = apr_table_get(r->headers_in, "Content-Length");
Packit 90a5c9
                        if (cl_a) {
Packit 90a5c9
                            apr_strtoff(&cl, cl_a, &end, 10);
Packit 90a5c9
                            /*
Packit 90a5c9
                             * The request body is of length > 0. We cannot
Packit 90a5c9
                             * retry with a direct connection since we already
Packit 90a5c9
                             * sent (parts of) the request body to the proxy
Packit 90a5c9
                             * and do not have any longer.
Packit 90a5c9
                             */
Packit 90a5c9
                            if (cl > 0) {
Packit 90a5c9
                                goto cleanup;
Packit 90a5c9
                            }
Packit 90a5c9
                        }
Packit 90a5c9
                        /*
Packit 90a5c9
                         * Transfer-Encoding was set as input header, so we had
Packit 90a5c9
                         * a request body. We cannot retry with a direct
Packit 90a5c9
                         * connection for the same reason as above.
Packit 90a5c9
                         */
Packit 90a5c9
                        if (apr_table_get(r->headers_in, "Transfer-Encoding")) {
Packit 90a5c9
                            goto cleanup;
Packit 90a5c9
                        }
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* otherwise, try it direct */
Packit 90a5c9
        /* N.B. what if we're behind a firewall, where we must use a proxy or
Packit 90a5c9
        * give up??
Packit 90a5c9
        */
Packit 90a5c9
Packit 90a5c9
        /* handle the scheme */
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01143)
Packit 90a5c9
                      "Running scheme %s handler (attempt %d)",
Packit 90a5c9
                      scheme, attempts);
Packit 90a5c9
        AP_PROXY_RUN(r, worker, conf, url, attempts);
Packit 90a5c9
        access_status = proxy_run_scheme_handler(r, worker, conf,
Packit 90a5c9
                                                 url, NULL, 0);
Packit 90a5c9
        if (access_status == OK
Packit 90a5c9
                || apr_table_get(r->notes, "proxy-error-override"))
Packit 90a5c9
            break;
Packit 90a5c9
        else if (access_status == HTTP_INTERNAL_SERVER_ERROR) {
Packit 90a5c9
            /* Unrecoverable server error.
Packit 90a5c9
             * We can not failover to another worker.
Packit 90a5c9
             * Mark the worker as unusable if member of load balancer
Packit 90a5c9
             */
Packit 90a5c9
            if (balancer
Packit 90a5c9
                && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
Packit 90a5c9
                worker->s->status |= PROXY_WORKER_IN_ERROR;
Packit 90a5c9
                worker->s->error_time = apr_time_now();
Packit 90a5c9
            }
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
        else if (access_status == HTTP_SERVICE_UNAVAILABLE) {
Packit 90a5c9
            /* Recoverable server error.
Packit 90a5c9
             * We can failover to another worker
Packit 90a5c9
             * Mark the worker as unusable if member of load balancer
Packit 90a5c9
             */
Packit 90a5c9
            if (balancer
Packit 90a5c9
                && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
Packit 90a5c9
                worker->s->status |= PROXY_WORKER_IN_ERROR;
Packit 90a5c9
                worker->s->error_time = apr_time_now();
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            /* Unrecoverable error.
Packit 90a5c9
             * Return the origin status code to the client.
Packit 90a5c9
             */
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
        /* Try again if the worker is unusable and the service is
Packit 90a5c9
         * unavailable.
Packit 90a5c9
         */
Packit 90a5c9
    } while (!PROXY_WORKER_IS_USABLE(worker) &&
Packit 90a5c9
             max_attempts > attempts++);
Packit 90a5c9
Packit 90a5c9
    if (DECLINED == access_status) {
Packit 90a5c9
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01144)
Packit 90a5c9
                      "No protocol handler was valid for the URL %s " 
Packit 90a5c9
                      "(scheme '%s'). "
Packit 90a5c9
                      "If you are using a DSO version of mod_proxy, make sure "
Packit 90a5c9
                      "the proxy submodules are included in the configuration "
Packit 90a5c9
                      "using LoadModule.", r->uri, scheme);
Packit 90a5c9
        access_status = HTTP_INTERNAL_SERVER_ERROR;
Packit 90a5c9
        goto cleanup;
Packit 90a5c9
    }
Packit 90a5c9
cleanup:
Packit 90a5c9
    /*
Packit 90a5c9
     * Save current r->status and set it to the value of access_status which
Packit 90a5c9
     * might be different (e.g. r->status could be HTTP_OK if e.g. we override
Packit 90a5c9
     * the error page on the proxy or if the error was not generated by the
Packit 90a5c9
     * backend itself but by the proxy e.g. a bad gateway) in order to give
Packit 90a5c9
     * ap_proxy_post_request a chance to act correctly on the status code.
Packit 90a5c9
     * But only do the above if access_status is not OK and not DONE, because
Packit 90a5c9
     * in this case r->status might contain the true status and overwriting
Packit 90a5c9
     * it with OK or DONE would be wrong.
Packit 90a5c9
     */
Packit 90a5c9
    if ((access_status != OK) && (access_status != DONE)) {
Packit 90a5c9
        saved_status = r->status;
Packit 90a5c9
        r->status = access_status;
Packit 90a5c9
        ap_proxy_post_request(worker, balancer, r, conf);
Packit 90a5c9
        /*
Packit 90a5c9
         * Only restore r->status if it has not been changed by
Packit 90a5c9
         * ap_proxy_post_request as we assume that this change was intentional.
Packit 90a5c9
         */
Packit 90a5c9
        if (r->status == access_status) {
Packit 90a5c9
            r->status = saved_status;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        ap_proxy_post_request(worker, balancer, r, conf);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    proxy_run_request_status(&access_status, r);
Packit 90a5c9
    AP_PROXY_RUN_FINISHED(r, attempts, access_status);
Packit 90a5c9
Packit 90a5c9
    return access_status;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* -------------------------------------------------------------- */
Packit 90a5c9
/* Setup configurable data */
Packit 90a5c9
Packit 90a5c9
static void * create_proxy_config(apr_pool_t *p, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
Packit 90a5c9
Packit 90a5c9
    ps->sec_proxy = apr_array_make(p, 10, sizeof(ap_conf_vector_t *));
Packit 90a5c9
    ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
Packit 90a5c9
    ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
Packit 90a5c9
    ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
Packit 90a5c9
    ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
Packit 90a5c9
    ps->workers = apr_array_make(p, 10, sizeof(proxy_worker));
Packit 90a5c9
    ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer));
Packit 90a5c9
    ps->forward = NULL;
Packit 90a5c9
    ps->reverse = NULL;
Packit 90a5c9
    ps->domain = NULL;
Packit 90a5c9
    ps->id = apr_psprintf(p, "p%x", 1); /* simply for storage size */
Packit 90a5c9
    ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
Packit 90a5c9
    ps->viaopt_set = 0; /* 0 means default */
Packit 90a5c9
    ps->req = 0;
Packit 90a5c9
    ps->max_balancers = 0;
Packit 90a5c9
    ps->bal_persist = 0;
Packit 90a5c9
    ps->inherit = 1;
Packit 90a5c9
    ps->inherit_set = 0;
Packit 90a5c9
    ps->ppinherit = 1;
Packit 90a5c9
    ps->ppinherit_set = 0;
Packit 90a5c9
    ps->bgrowth = 5;
Packit 90a5c9
    ps->bgrowth_set = 0;
Packit 90a5c9
    ps->req_set = 0;
Packit 90a5c9
    ps->recv_buffer_size = 0; /* this default was left unset for some reason */
Packit 90a5c9
    ps->recv_buffer_size_set = 0;
Packit 90a5c9
    ps->io_buffer_size = AP_IOBUFSIZE;
Packit 90a5c9
    ps->io_buffer_size_set = 0;
Packit 90a5c9
    ps->maxfwd = DEFAULT_MAX_FORWARDS;
Packit 90a5c9
    ps->maxfwd_set = 0;
Packit 90a5c9
    ps->timeout = 0;
Packit 90a5c9
    ps->timeout_set = 0;
Packit 90a5c9
    ps->badopt = bad_error;
Packit 90a5c9
    ps->badopt_set = 0;
Packit 90a5c9
    ps->source_address = NULL;
Packit 90a5c9
    ps->source_address_set = 0;
Packit 90a5c9
    apr_pool_create_ex(&ps->pool, p, NULL, NULL);
Packit 90a5c9
Packit 90a5c9
    return ps;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_array_header_t *merge_balancers(apr_pool_t *p,
Packit 90a5c9
                                           apr_array_header_t *base,
Packit 90a5c9
                                           apr_array_header_t *overrides)
Packit 90a5c9
{
Packit 90a5c9
    proxy_balancer *b1;
Packit 90a5c9
    proxy_balancer *b2;
Packit 90a5c9
    proxy_balancer tmp;
Packit 90a5c9
    int x, y, found;
Packit 90a5c9
    apr_array_header_t *tocopy = apr_array_make(p, 1, sizeof(proxy_balancer));
Packit 90a5c9
Packit 90a5c9
    /* Check if the balancer is defined in both override and base configs:
Packit 90a5c9
     * a) If it is, Create copy of base balancer and change the configuration
Packit 90a5c9
     *    which can be changed by ProxyPass.
Packit 90a5c9
     * b) Otherwise, copy the balancer to tocopy array and merge it later.
Packit 90a5c9
     */
Packit 90a5c9
    b1 = (proxy_balancer *) base->elts;
Packit 90a5c9
    for (y = 0; y < base->nelts; y++) {
Packit 90a5c9
        b2 = (proxy_balancer *) overrides->elts;
Packit 90a5c9
        for (x = 0, found = 0; x < overrides->nelts; x++) {
Packit 90a5c9
            if (b1->hash.def == b2->hash.def && b1->hash.fnv == b2->hash.fnv) {
Packit 90a5c9
                tmp = *b2;
Packit 90a5c9
                *b2 = *b1;
Packit 90a5c9
                b2->s = tmp.s;
Packit 90a5c9
Packit 90a5c9
                /* For shared memory entries, b2->s belongs to override
Packit 90a5c9
                 * balancer, so if some entry is not set there, we have to
Packit 90a5c9
                 * update it according to the base balancer. */
Packit 90a5c9
                if (*b2->s->sticky == 0 && *b1->s->sticky) {
Packit 90a5c9
                    PROXY_STRNCPY(b2->s->sticky_path, b1->s->sticky_path);
Packit 90a5c9
                    PROXY_STRNCPY(b2->s->sticky, b1->s->sticky);
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->sticky_separator_set
Packit 90a5c9
                    && b1->s->sticky_separator_set) {
Packit 90a5c9
                    b2->s->sticky_separator_set = b1->s->sticky_separator_set;
Packit 90a5c9
                    b2->s->sticky_separator = b1->s->sticky_separator;
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->timeout && b1->s->timeout) {
Packit 90a5c9
                    b2->s->timeout = b1->s->timeout;
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->max_attempts_set && b1->s->max_attempts_set) {
Packit 90a5c9
                    b2->s->max_attempts_set = b1->s->max_attempts_set;
Packit 90a5c9
                    b2->s->max_attempts = b1->s->max_attempts;
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->nonce_set && b1->s->nonce_set) {
Packit 90a5c9
                    b2->s->nonce_set = b1->s->nonce_set;
Packit 90a5c9
                    PROXY_STRNCPY(b2->s->nonce, b1->s->nonce);
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->sticky_force_set && b1->s->sticky_force_set) {
Packit 90a5c9
                    b2->s->sticky_force_set = b1->s->sticky_force_set;
Packit 90a5c9
                    b2->s->sticky_force = b1->s->sticky_force;
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->scolonsep_set && b1->s->scolonsep_set) {
Packit 90a5c9
                    b2->s->scolonsep_set = b1->s->scolonsep_set;
Packit 90a5c9
                    b2->s->scolonsep = b1->s->scolonsep;
Packit 90a5c9
                }
Packit 90a5c9
                if (!b2->s->forcerecovery_set && b1->s->forcerecovery_set) {
Packit 90a5c9
                    b2->s->forcerecovery_set = b1->s->forcerecovery_set;
Packit 90a5c9
                    b2->s->forcerecovery = b1->s->forcerecovery;
Packit 90a5c9
                }
Packit 90a5c9
Packit 90a5c9
                /* For non-shared memory entries, b2 is copy of b1, so we have
Packit 90a5c9
                 * to use tmp copy of b1 to detect changes done in override. */
Packit 90a5c9
                if (tmp.lbmethod_set) {
Packit 90a5c9
                    b2->lbmethod_set = tmp.lbmethod_set;
Packit 90a5c9
                    b2->lbmethod = tmp.lbmethod;
Packit 90a5c9
                }
Packit 90a5c9
                if (tmp.growth_set) {
Packit 90a5c9
                    b2->growth_set = tmp.growth_set;
Packit 90a5c9
                    b2->growth = tmp.growth;
Packit 90a5c9
                }
Packit 90a5c9
                if (tmp.failontimeout_set) {
Packit 90a5c9
                    b2->failontimeout_set = tmp.failontimeout_set;
Packit 90a5c9
                    b2->failontimeout = tmp.failontimeout;
Packit 90a5c9
                }
Packit 90a5c9
                if (!apr_is_empty_array(tmp.errstatuses)) {
Packit 90a5c9
                    apr_array_cat(tmp.errstatuses, b2->errstatuses);
Packit 90a5c9
                    b2->errstatuses = tmp.errstatuses;
Packit 90a5c9
                }
Packit 90a5c9
Packit 90a5c9
                found = 1;
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
            b2++;
Packit 90a5c9
        }
Packit 90a5c9
        if (!found) {
Packit 90a5c9
            *(proxy_balancer *)apr_array_push(tocopy) = *b1;
Packit 90a5c9
        }
Packit 90a5c9
        b1++;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return apr_array_append(p, tocopy, overrides);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
Packit 90a5c9
    proxy_server_conf *base = (proxy_server_conf *) basev;
Packit 90a5c9
    proxy_server_conf *overrides = (proxy_server_conf *) overridesv;
Packit 90a5c9
Packit 90a5c9
    ps->inherit = (overrides->inherit_set == 0) ? base->inherit : overrides->inherit;
Packit 90a5c9
    ps->inherit_set = overrides->inherit_set || base->inherit_set;
Packit 90a5c9
Packit 90a5c9
    ps->ppinherit = (overrides->ppinherit_set == 0) ? base->ppinherit : overrides->ppinherit;
Packit 90a5c9
    ps->ppinherit_set = overrides->ppinherit_set || base->ppinherit_set;
Packit 90a5c9
Packit 90a5c9
    if (ps->ppinherit) {
Packit 90a5c9
        ps->proxies = apr_array_append(p, base->proxies, overrides->proxies);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        ps->proxies = overrides->proxies;
Packit 90a5c9
    }
Packit 90a5c9
    ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
Packit 90a5c9
    ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
Packit 90a5c9
    ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
Packit 90a5c9
    ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
Packit 90a5c9
    if (ps->inherit || ps->ppinherit) {
Packit 90a5c9
        ps->workers = apr_array_append(p, base->workers, overrides->workers);
Packit 90a5c9
        ps->balancers = merge_balancers(p, base->balancers, overrides->balancers);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        ps->workers = overrides->workers;
Packit 90a5c9
        ps->balancers = overrides->balancers;
Packit 90a5c9
    }
Packit 90a5c9
    ps->forward = overrides->forward ? overrides->forward : base->forward;
Packit 90a5c9
    ps->reverse = overrides->reverse ? overrides->reverse : base->reverse;
Packit 90a5c9
Packit 90a5c9
    ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
Packit 90a5c9
    ps->id = (overrides->id == NULL) ? base->id : overrides->id;
Packit 90a5c9
    ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
Packit 90a5c9
    ps->viaopt_set = overrides->viaopt_set || base->viaopt_set;
Packit 90a5c9
    ps->req = (overrides->req_set == 0) ? base->req : overrides->req;
Packit 90a5c9
    ps->req_set = overrides->req_set || base->req_set;
Packit 90a5c9
    ps->bgrowth = (overrides->bgrowth_set == 0) ? base->bgrowth : overrides->bgrowth;
Packit 90a5c9
    ps->bgrowth_set = overrides->bgrowth_set || base->bgrowth_set;
Packit 90a5c9
    ps->max_balancers = overrides->max_balancers || base->max_balancers;
Packit 90a5c9
    ps->bal_persist = overrides->bal_persist;
Packit 90a5c9
    ps->recv_buffer_size = (overrides->recv_buffer_size_set == 0) ? base->recv_buffer_size : overrides->recv_buffer_size;
Packit 90a5c9
    ps->recv_buffer_size_set = overrides->recv_buffer_size_set || base->recv_buffer_size_set;
Packit 90a5c9
    ps->io_buffer_size = (overrides->io_buffer_size_set == 0) ? base->io_buffer_size : overrides->io_buffer_size;
Packit 90a5c9
    ps->io_buffer_size_set = overrides->io_buffer_size_set || base->io_buffer_size_set;
Packit 90a5c9
    ps->maxfwd = (overrides->maxfwd_set == 0) ? base->maxfwd : overrides->maxfwd;
Packit 90a5c9
    ps->maxfwd_set = overrides->maxfwd_set || base->maxfwd_set;
Packit 90a5c9
    ps->timeout = (overrides->timeout_set == 0) ? base->timeout : overrides->timeout;
Packit 90a5c9
    ps->timeout_set = overrides->timeout_set || base->timeout_set;
Packit 90a5c9
    ps->badopt = (overrides->badopt_set == 0) ? base->badopt : overrides->badopt;
Packit 90a5c9
    ps->badopt_set = overrides->badopt_set || base->badopt_set;
Packit 90a5c9
    ps->proxy_status = (overrides->proxy_status_set == 0) ? base->proxy_status : overrides->proxy_status;
Packit 90a5c9
    ps->proxy_status_set = overrides->proxy_status_set || base->proxy_status_set;
Packit 90a5c9
    ps->source_address = (overrides->source_address_set == 0) ? base->source_address : overrides->source_address;
Packit 90a5c9
    ps->source_address_set = overrides->source_address_set || base->source_address_set;
Packit 90a5c9
    ps->pool = base->pool;
Packit 90a5c9
    return ps;
Packit 90a5c9
}
Packit 90a5c9
static const char *set_source_address(cmd_parms *parms, void *dummy,
Packit 90a5c9
                                      const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
        ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
    struct apr_sockaddr_t *addr;
Packit 90a5c9
Packit 90a5c9
    if (APR_SUCCESS == apr_sockaddr_info_get(&addr, arg, APR_UNSPEC, 0, 0,
Packit 90a5c9
                                             psf->pool)) {
Packit 90a5c9
        psf->source_address = addr;
Packit 90a5c9
        psf->source_address_set = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return "ProxySourceAddress invalid value";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void *create_proxy_dir_config(apr_pool_t *p, char *dummy)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *new =
Packit 90a5c9
        (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
Packit 90a5c9
Packit 90a5c9
    /* Filled in by proxysection, when applicable */
Packit 90a5c9
Packit 90a5c9
    /* Put these in the dir config so they work inside <Location> */
Packit 90a5c9
    new->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
Packit 90a5c9
    new->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
Packit 90a5c9
    new->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
Packit 90a5c9
    new->preserve_host_set = 0;
Packit 90a5c9
    new->preserve_host = 0;
Packit 90a5c9
    new->interpolate_env = -1; /* unset */
Packit 90a5c9
    new->error_override = 0;
Packit 90a5c9
    new->error_override_set = 0;
Packit 90a5c9
    new->add_forwarded_headers = 1;
Packit 90a5c9
    new->add_forwarded_headers_set = 0;
Packit f02de7
    new->forward_100_continue = 1;
Packit f02de7
    new->forward_100_continue_set = 0;
Packit 90a5c9
Packit 90a5c9
    return (void *) new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *new = (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
Packit 90a5c9
    proxy_dir_conf *add = (proxy_dir_conf *) addv;
Packit 90a5c9
    proxy_dir_conf *base = (proxy_dir_conf *) basev;
Packit 90a5c9
Packit 90a5c9
    new->p = add->p;
Packit 90a5c9
    new->p_is_fnmatch = add->p_is_fnmatch;
Packit 90a5c9
    new->r = add->r;
Packit 90a5c9
    new->refs = add->refs;
Packit 90a5c9
Packit 90a5c9
    /* Put these in the dir config so they work inside <Location> */
Packit 90a5c9
    new->raliases = apr_array_append(p, base->raliases, add->raliases);
Packit 90a5c9
    new->cookie_paths
Packit 90a5c9
        = apr_array_append(p, base->cookie_paths, add->cookie_paths);
Packit 90a5c9
    new->cookie_domains
Packit 90a5c9
        = apr_array_append(p, base->cookie_domains, add->cookie_domains);
Packit 90a5c9
    new->interpolate_env = (add->interpolate_env == -1) ? base->interpolate_env
Packit 90a5c9
                                                        : add->interpolate_env;
Packit 90a5c9
    new->preserve_host = (add->preserve_host_set == 0) ? base->preserve_host
Packit 90a5c9
                                                        : add->preserve_host;
Packit 90a5c9
    new->preserve_host_set = add->preserve_host_set || base->preserve_host_set;
Packit 90a5c9
    new->error_override = (add->error_override_set == 0) ? base->error_override
Packit 90a5c9
                                                        : add->error_override;
Packit 90a5c9
    new->error_override_set = add->error_override_set || base->error_override_set;
Packit 90a5c9
    new->alias = (add->alias_set == 0) ? base->alias : add->alias;
Packit 90a5c9
    new->alias_set = add->alias_set || base->alias_set;
Packit 90a5c9
    new->add_forwarded_headers =
Packit 90a5c9
        (add->add_forwarded_headers_set == 0) ? base->add_forwarded_headers
Packit 90a5c9
        : add->add_forwarded_headers;
Packit 90a5c9
    new->add_forwarded_headers_set = add->add_forwarded_headers_set
Packit 90a5c9
        || base->add_forwarded_headers_set;
Packit f02de7
    new->forward_100_continue =
Packit f02de7
        (add->forward_100_continue_set == 0) ? base->forward_100_continue
Packit f02de7
                                             : add->forward_100_continue;
Packit f02de7
    new->forward_100_continue_set = add->forward_100_continue_set
Packit f02de7
                                    || base->forward_100_continue_set;
Packit 90a5c9
    
Packit 90a5c9
    return new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s = cmd->server;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
    (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
    struct proxy_remote *new;
Packit 90a5c9
    char *p, *q;
Packit 90a5c9
    char *r, *f, *scheme;
Packit 90a5c9
    ap_regex_t *reg = NULL;
Packit 90a5c9
    int port;
Packit 90a5c9
Packit 90a5c9
    r = apr_pstrdup(cmd->pool, r1);
Packit 90a5c9
    scheme = apr_pstrdup(cmd->pool, r1);
Packit 90a5c9
    f = apr_pstrdup(cmd->pool, f1);
Packit 90a5c9
    p = strchr(r, ':');
Packit 90a5c9
    if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0') {
Packit 90a5c9
        if (regex)
Packit 90a5c9
            return "ProxyRemoteMatch: Bad syntax for a remote proxy server";
Packit 90a5c9
        else
Packit 90a5c9
            return "ProxyRemote: Bad syntax for a remote proxy server";
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        scheme[p-r] = 0;
Packit 90a5c9
    }
Packit 90a5c9
    q = strchr(p + 3, ':');
Packit 90a5c9
    if (q != NULL) {
Packit 90a5c9
        if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {
Packit 90a5c9
            if (regex)
Packit 90a5c9
                return "ProxyRemoteMatch: Bad syntax for a remote proxy server (bad port number)";
Packit 90a5c9
            else
Packit 90a5c9
                return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
Packit 90a5c9
        }
Packit 90a5c9
        *q = '\0';
Packit 90a5c9
    }
Packit 90a5c9
    else
Packit 90a5c9
        port = -1;
Packit 90a5c9
    *p = '\0';
Packit 90a5c9
    if (regex) {
Packit 90a5c9
        reg = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
Packit 90a5c9
        if (!reg)
Packit 90a5c9
            return "Regular expression for ProxyRemoteMatch could not be compiled.";
Packit 90a5c9
    }
Packit 90a5c9
    else
Packit 90a5c9
        if (strchr(f, ':') == NULL)
Packit 90a5c9
            ap_str_tolower(f);      /* lowercase scheme */
Packit 90a5c9
    ap_str_tolower(p + 3);      /* lowercase hostname */
Packit 90a5c9
Packit 90a5c9
    if (port == -1) {
Packit 90a5c9
        port = apr_uri_port_of_scheme(scheme);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    new = apr_array_push(conf->proxies);
Packit 90a5c9
    new->scheme = f;
Packit 90a5c9
    new->protocol = r;
Packit 90a5c9
    new->hostname = p + 3;
Packit 90a5c9
    new->port = port;
Packit 90a5c9
    new->regexp = reg;
Packit 90a5c9
    new->use_regex = regex;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
Packit 90a5c9
{
Packit 90a5c9
    return add_proxy(cmd, dummy, f1, r1, 0);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
Packit 90a5c9
{
Packit 90a5c9
    return add_proxy(cmd, dummy, f1, r1, 1);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
Packit 90a5c9
{
Packit 90a5c9
    const char *ptr;
Packit 90a5c9
    /*
Packit 90a5c9
     * We could be passed a URL during the config stage that contains
Packit 90a5c9
     * the UDS path... ignore it
Packit 90a5c9
     */
Packit 90a5c9
    if (!strncasecmp(url, "unix:", 5) &&
Packit 90a5c9
        ((ptr = ap_strchr_c(url, '|')) != NULL)) {
Packit 90a5c9
        /* move past the 'unix:...|' UDS path info */
Packit 90a5c9
        const char *ret, *c;
Packit 90a5c9
Packit 90a5c9
        ret = ptr + 1;
Packit 90a5c9
        /* special case: "unix:....|scheme:" is OK, expand
Packit 90a5c9
         * to "unix:....|scheme://localhost"
Packit 90a5c9
         * */
Packit 90a5c9
        c = ap_strchr_c(ret, ':');
Packit 90a5c9
        if (c == NULL) {
Packit 90a5c9
            return NULL;
Packit 90a5c9
        }
Packit 90a5c9
        if (c[1] == '\0') {
Packit 90a5c9
            return apr_pstrcat(p, ret, "//localhost", NULL);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            return ret;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return url;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *dconf = (proxy_dir_conf *)dummy;
Packit 90a5c9
    server_rec *s = cmd->server;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
    (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
    struct proxy_alias *new;
Packit 90a5c9
    char *f = cmd->path;
Packit 90a5c9
    char *r = NULL;
Packit 90a5c9
    char *word;
Packit 90a5c9
    apr_table_t *params = apr_table_make(cmd->pool, 5);
Packit 90a5c9
    const apr_array_header_t *arr;
Packit 90a5c9
    const apr_table_entry_t *elts;
Packit 90a5c9
    int i;
Packit 90a5c9
    int use_regex = is_regex;
Packit 90a5c9
    unsigned int flags = 0;
Packit 90a5c9
    const char *err;
Packit 90a5c9
Packit 90a5c9
    err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES);
Packit 90a5c9
    if (err) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    while (*arg) {
Packit 90a5c9
        word = ap_getword_conf(cmd->pool, &arg;;
Packit 90a5c9
        if (!f) {
Packit 90a5c9
            if (!strcmp(word, "~")) {
Packit 90a5c9
                if (is_regex) {
Packit 90a5c9
                    return "ProxyPassMatch invalid syntax ('~' usage).";
Packit 90a5c9
                }
Packit 90a5c9
                use_regex = 1;
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
            f = word;
Packit 90a5c9
        }
Packit 90a5c9
        else if (!r) {
Packit 90a5c9
            r = word;
Packit 90a5c9
        }
Packit 90a5c9
        else if (!strcasecmp(word,"nocanon")) {
Packit 90a5c9
            flags |= PROXYPASS_NOCANON;
Packit 90a5c9
        }
Packit 90a5c9
        else if (!strcasecmp(word,"interpolate")) {
Packit 90a5c9
            flags |= PROXYPASS_INTERPOLATE;
Packit 90a5c9
        }
Packit 90a5c9
        else if (!strcasecmp(word,"noquery")) {
Packit 90a5c9
            flags |= PROXYPASS_NOQUERY;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            char *val = strchr(word, '=');
Packit 90a5c9
            if (!val) {
Packit 90a5c9
                if (cmd->path) {
Packit 90a5c9
                    if (*r == '/') {
Packit 90a5c9
                        return "ProxyPass|ProxyPassMatch can not have a path when defined in "
Packit 90a5c9
                               "a location.";
Packit 90a5c9
                    }
Packit 90a5c9
                    else {
Packit 90a5c9
                        return "Invalid ProxyPass|ProxyPassMatch parameter. Parameter must "
Packit 90a5c9
                               "be in the form 'key=value'.";
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    return "Invalid ProxyPass|ProxyPassMatch parameter. Parameter must be "
Packit 90a5c9
                           "in the form 'key=value'.";
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            else
Packit 90a5c9
                *val++ = '\0';
Packit 90a5c9
            apr_table_setn(params, word, val);
Packit 90a5c9
        }
Packit 90a5c9
    };
Packit 90a5c9
Packit 90a5c9
    if (r == NULL) {
Packit 90a5c9
        return "ProxyPass|ProxyPassMatch needs a path when not defined in a location";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* if per directory, save away the single alias */
Packit 90a5c9
    if (cmd->path) {
Packit 90a5c9
        dconf->alias = apr_pcalloc(cmd->pool, sizeof(struct proxy_alias));
Packit 90a5c9
        dconf->alias_set = 1;
Packit 90a5c9
        new = dconf->alias;
Packit 90a5c9
        if (apr_fnmatch_test(f)) {
Packit 90a5c9
            use_regex = 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    /* if per server, add to the alias array */
Packit 90a5c9
    else {
Packit 90a5c9
        new = apr_array_push(conf->aliases);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    new->fake = apr_pstrdup(cmd->pool, f);
Packit 90a5c9
    new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r));
Packit 90a5c9
    new->flags = flags;
Packit 90a5c9
    if (use_regex) {
Packit 90a5c9
        new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
Packit 90a5c9
        if (new->regex == NULL)
Packit 90a5c9
            return "Regular expression could not be compiled.";
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        new->regex = NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (r[0] == '!' && r[1] == '\0')
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    arr = apr_table_elts(params);
Packit 90a5c9
    elts = (const apr_table_entry_t *)arr->elts;
Packit 90a5c9
    /* Distinguish the balancer from worker */
Packit 90a5c9
    if (ap_proxy_valid_balancer_name(r, 9)) {
Packit 90a5c9
        proxy_balancer *balancer = ap_proxy_get_balancer(cmd->pool, conf, r, 0);
Packit 90a5c9
        char *fake_copy;
Packit 90a5c9
Packit 90a5c9
        /*
Packit 90a5c9
         * In the regex case supplying a fake URL doesn't make sense as it
Packit 90a5c9
         * cannot be parsed anyway with apr_uri_parse later on in
Packit 90a5c9
         * ap_proxy_define_balancer / ap_proxy_update_balancer
Packit 90a5c9
         */
Packit 90a5c9
        if (use_regex) {
Packit 90a5c9
            fake_copy = NULL;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            fake_copy = f;
Packit 90a5c9
        }
Packit 90a5c9
        if (!balancer) {
Packit 90a5c9
            const char *err = ap_proxy_define_balancer(cmd->pool, &balancer, conf, r, fake_copy, 0);
Packit 90a5c9
            if (err)
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ap_proxy_update_balancer(cmd->pool, balancer, fake_copy);
Packit 90a5c9
        }
Packit 90a5c9
        for (i = 0; i < arr->nelts; i++) {
Packit 90a5c9
            const char *err = set_balancer_param(conf, cmd->pool, balancer, elts[i].key,
Packit 90a5c9
                                                 elts[i].val);
Packit 90a5c9
            if (err)
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
Packit 90a5c9
        }
Packit 90a5c9
        new->balancer = balancer;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->pool, r));
Packit 90a5c9
        int reuse = 0;
Packit 90a5c9
        if (!worker) {
Packit 90a5c9
            const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0);
Packit 90a5c9
            if (err)
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
Packit 90a5c9
Packit 90a5c9
            PROXY_COPY_CONF_PARAMS(worker, conf);
Packit 90a5c9
        } else {
Packit 90a5c9
            reuse = 1;
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145)
Packit 90a5c9
                         "Sharing worker '%s' instead of creating new worker '%s'",
Packit 90a5c9
                         ap_proxy_worker_name(cmd->pool, worker), new->real);
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        for (i = 0; i < arr->nelts; i++) {
Packit 90a5c9
            if (reuse) {
Packit 90a5c9
                ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01146)
Packit 90a5c9
                             "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing",
Packit 90a5c9
                             elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker));
Packit 90a5c9
            } else {
Packit 90a5c9
                const char *err = set_worker_param(cmd->pool, s, worker, elts[i].key,
Packit 90a5c9
                                                   elts[i].val);
Packit 90a5c9
                if (err)
Packit 90a5c9
                    return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    add_pass_noregex(cmd_parms *cmd, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return add_pass(cmd, dummy, arg, 0);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    add_pass_regex(cmd_parms *cmd, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    return add_pass(cmd, dummy, arg, 1);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static const char * add_pass_reverse(cmd_parms *cmd, void *dconf, const char *f,
Packit 90a5c9
                                     const char *r, const char *i)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *conf = dconf;
Packit 90a5c9
    struct proxy_alias *new;
Packit 90a5c9
    const char *fake;
Packit 90a5c9
    const char *real;
Packit 90a5c9
    const char *interp;
Packit 90a5c9
    const char *err;
Packit 90a5c9
Packit 90a5c9
    err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES);
Packit 90a5c9
    if (err) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (cmd->path == NULL) {
Packit 90a5c9
        if (r == NULL || !strcasecmp(r, "interpolate")) {
Packit 90a5c9
            return "ProxyPassReverse needs a path when not defined in a location";
Packit 90a5c9
        }
Packit 90a5c9
        fake = f;
Packit 90a5c9
        real = r;
Packit 90a5c9
        interp = i;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        if (r && strcasecmp(r, "interpolate")) {
Packit 90a5c9
            return "ProxyPassReverse can not have a path when defined in a location";
Packit 90a5c9
        }
Packit 90a5c9
        fake = cmd->path;
Packit 90a5c9
        real = f;
Packit 90a5c9
        interp = r;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    new = apr_array_push(conf->raliases);
Packit 90a5c9
    new->fake = fake;
Packit 90a5c9
    new->real = real;
Packit 90a5c9
    new->flags = interp ? PROXYPASS_INTERPOLATE : 0;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
static const char* cookie_path(cmd_parms *cmd, void *dconf, const char *f,
Packit 90a5c9
                               const char *r, const char *interp)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *conf = dconf;
Packit 90a5c9
    struct proxy_alias *new;
Packit 90a5c9
Packit 90a5c9
    new = apr_array_push(conf->cookie_paths);
Packit 90a5c9
    new->fake = f;
Packit 90a5c9
    new->real = r;
Packit 90a5c9
    new->flags = interp ? PROXYPASS_INTERPOLATE : 0;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
static const char* cookie_domain(cmd_parms *cmd, void *dconf, const char *f,
Packit 90a5c9
                                 const char *r, const char *interp)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *conf = dconf;
Packit 90a5c9
    struct proxy_alias *new;
Packit 90a5c9
Packit 90a5c9
    new = apr_array_push(conf->cookie_domains);
Packit 90a5c9
    new->fake = f;
Packit 90a5c9
    new->real = r;
Packit 90a5c9
    new->flags = interp ? PROXYPASS_INTERPOLATE : 0;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s = parms->server;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
    ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
    struct noproxy_entry *new;
Packit 90a5c9
    struct noproxy_entry *list = (struct noproxy_entry *) conf->noproxies->elts;
Packit 90a5c9
    struct apr_sockaddr_t *addr;
Packit 90a5c9
    int found = 0;
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    /* Don't duplicate entries */
Packit 90a5c9
    for (i = 0; i < conf->noproxies->nelts; i++) {
Packit 90a5c9
        if (strcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */
Packit 90a5c9
            found = 1;
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!found) {
Packit 90a5c9
        new = apr_array_push(conf->noproxies);
Packit 90a5c9
        new->name = arg;
Packit 90a5c9
        if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
Packit 90a5c9
            new->addr = addr;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            new->addr = NULL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* Similar to set_proxy_exclude(), but defining directly connected hosts,
Packit 90a5c9
 * which should never be accessed via the configured ProxyRemote servers
Packit 90a5c9
 */
Packit 90a5c9
static const char *
Packit 90a5c9
    set_proxy_dirconn(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s = parms->server;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
    ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
    struct dirconn_entry *New;
Packit 90a5c9
    struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
Packit 90a5c9
    int found = 0;
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    /* Don't duplicate entries */
Packit 90a5c9
    for (i = 0; i < conf->dirconn->nelts; i++) {
Packit 90a5c9
        if (strcasecmp(arg, list[i].name) == 0) {
Packit 90a5c9
            found = 1;
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!found) {
Packit 90a5c9
        New = apr_array_push(conf->dirconn);
Packit 90a5c9
        New->name = apr_pstrdup(parms->pool, arg);
Packit 90a5c9
        New->hostaddr = NULL;
Packit 90a5c9
Packit 90a5c9
        if (ap_proxy_is_ipaddr(New, parms->pool)) {
Packit 90a5c9
#if DEBUGGING
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(03018)
Packit 90a5c9
                         "Parsed addr %s", inet_ntoa(New->addr));
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(03019)
Packit 90a5c9
                         "Parsed mask %s", inet_ntoa(New->mask));
Packit 90a5c9
#endif
Packit 90a5c9
        }
Packit 90a5c9
        else if (ap_proxy_is_domainname(New, parms->pool)) {
Packit 90a5c9
            ap_str_tolower(New->name);
Packit 90a5c9
#if DEBUGGING
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(03020)
Packit 90a5c9
                         "Parsed domain %s", New->name);
Packit 90a5c9
#endif
Packit 90a5c9
        }
Packit 90a5c9
        else if (ap_proxy_is_hostname(New, parms->pool)) {
Packit 90a5c9
            ap_str_tolower(New->name);
Packit 90a5c9
#if DEBUGGING
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(03021)
Packit 90a5c9
                         "Parsed host %s", New->name);
Packit 90a5c9
#endif
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ap_proxy_is_word(New, parms->pool);
Packit 90a5c9
#if DEBUGGING
Packit 90a5c9
            fprintf(stderr, "Parsed word %s\n", New->name);
Packit 90a5c9
#endif
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_proxy_domain(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    if (arg[0] != '.')
Packit 90a5c9
        return "ProxyDomain: domain name must start with a dot.";
Packit 90a5c9
Packit 90a5c9
    psf->domain = arg;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_proxy_req(cmd_parms *parms, void *dummy, int flag)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    psf->req = flag;
Packit 90a5c9
    psf->req_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_proxy_error_override(cmd_parms *parms, void *dconf, int flag)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    conf->error_override = flag;
Packit 90a5c9
    conf->error_override_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
static const char *
Packit 90a5c9
   add_proxy_http_headers(cmd_parms *parms, void *dconf, int flag)
Packit 90a5c9
{
Packit 90a5c9
   proxy_dir_conf *conf = dconf;
Packit 90a5c9
   conf->add_forwarded_headers = flag;
Packit 90a5c9
   conf->add_forwarded_headers_set = 1;
Packit 90a5c9
   return NULL;
Packit 90a5c9
}
Packit 90a5c9
static const char *
Packit 90a5c9
    set_preserve_host(cmd_parms *parms, void *dconf, int flag)
Packit 90a5c9
{
Packit 90a5c9
    proxy_dir_conf *conf = dconf;
Packit 90a5c9
Packit 90a5c9
    conf->preserve_host = flag;
Packit 90a5c9
    conf->preserve_host_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit f02de7
static const char *
Packit f02de7
   forward_100_continue(cmd_parms *parms, void *dconf, int flag)
Packit f02de7
{
Packit f02de7
   proxy_dir_conf *conf = dconf;
Packit f02de7
   conf->forward_100_continue = flag;
Packit f02de7
   conf->forward_100_continue_set = 1;
Packit f02de7
   return NULL;
Packit f02de7
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_recv_buffer_size(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
    int s = atoi(arg);
Packit 90a5c9
    if (s < 512 && s != 0) {
Packit 90a5c9
        return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    psf->recv_buffer_size = s;
Packit 90a5c9
    psf->recv_buffer_size_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_io_buffer_size(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
    long s = atol(arg);
Packit 90a5c9
    if (s < 512 && s) {
Packit 90a5c9
        return "ProxyIOBufferSize must be >= 512 bytes, or 0 for system default.";
Packit 90a5c9
    }
Packit 90a5c9
    psf->io_buffer_size = (s ? s : AP_IOBUFSIZE);
Packit 90a5c9
    psf->io_buffer_size_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_max_forwards(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
    long s = atol(arg);
Packit 90a5c9
Packit 90a5c9
    psf->maxfwd = s;
Packit 90a5c9
    psf->maxfwd_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
static const char*
Packit 90a5c9
    set_proxy_timeout(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
    int timeout;
Packit 90a5c9
Packit 90a5c9
    timeout = atoi(arg);
Packit 90a5c9
    if (timeout<1) {
Packit 90a5c9
        return "Proxy Timeout must be at least 1 second.";
Packit 90a5c9
    }
Packit 90a5c9
    psf->timeout_set = 1;
Packit 90a5c9
    psf->timeout = apr_time_from_sec(timeout);
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char*
Packit 90a5c9
    set_via_opt(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    if (strcasecmp(arg, "Off") == 0)
Packit 90a5c9
        psf->viaopt = via_off;
Packit 90a5c9
    else if (strcasecmp(arg, "On") == 0)
Packit 90a5c9
        psf->viaopt = via_on;
Packit 90a5c9
    else if (strcasecmp(arg, "Block") == 0)
Packit 90a5c9
        psf->viaopt = via_block;
Packit 90a5c9
    else if (strcasecmp(arg, "Full") == 0)
Packit 90a5c9
        psf->viaopt = via_full;
Packit 90a5c9
    else {
Packit 90a5c9
        return "ProxyVia must be one of: "
Packit 90a5c9
            "off | on | full | block";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    psf->viaopt_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char*
Packit 90a5c9
    set_bad_opt(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    if (strcasecmp(arg, "IsError") == 0)
Packit 90a5c9
        psf->badopt = bad_error;
Packit 90a5c9
    else if (strcasecmp(arg, "Ignore") == 0)
Packit 90a5c9
        psf->badopt = bad_ignore;
Packit 90a5c9
    else if (strcasecmp(arg, "StartBody") == 0)
Packit 90a5c9
        psf->badopt = bad_body;
Packit 90a5c9
    else {
Packit 90a5c9
        return "ProxyBadHeader must be one of: "
Packit 90a5c9
            "IsError | Ignore | StartBody";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    psf->badopt_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char*
Packit 90a5c9
    set_status_opt(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    if (strcasecmp(arg, "Off") == 0)
Packit 90a5c9
        psf->proxy_status = status_off;
Packit 90a5c9
    else if (strcasecmp(arg, "On") == 0)
Packit 90a5c9
        psf->proxy_status = status_on;
Packit 90a5c9
    else if (strcasecmp(arg, "Full") == 0)
Packit 90a5c9
        psf->proxy_status = status_full;
Packit 90a5c9
    else {
Packit 90a5c9
        return "ProxyStatus must be one of: "
Packit 90a5c9
            "off | on | full";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    psf->proxy_status_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *set_bgrowth(cmd_parms *parms, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    int growth = atoi(arg);
Packit 90a5c9
    if (growth < 0 || growth > 1000) {
Packit 90a5c9
        return "BalancerGrowth must be between 0 and 1000";
Packit 90a5c9
    }
Packit 90a5c9
    psf->bgrowth = growth;
Packit 90a5c9
    psf->bgrowth_set = 1;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *set_persist(cmd_parms *parms, void *dummy, int flag)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    psf->bal_persist = flag;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *set_inherit(cmd_parms *parms, void *dummy, int flag)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    psf->inherit = flag;
Packit 90a5c9
    psf->inherit_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *set_ppinherit(cmd_parms *parms, void *dummy, int flag)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *psf =
Packit 90a5c9
    ap_get_module_config(parms->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    psf->ppinherit = flag;
Packit 90a5c9
    psf->ppinherit_set = 1;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s = cmd->server;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
    ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
    proxy_balancer *balancer;
Packit 90a5c9
    proxy_worker *worker;
Packit 90a5c9
    char *path = cmd->path;
Packit 90a5c9
    char *name = NULL;
Packit 90a5c9
    char *word;
Packit 90a5c9
    apr_table_t *params = apr_table_make(cmd->pool, 5);
Packit 90a5c9
    const apr_array_header_t *arr;
Packit 90a5c9
    const apr_table_entry_t *elts;
Packit 90a5c9
    int reuse = 0;
Packit 90a5c9
    int i;
Packit 90a5c9
    /* XXX: Should this be NOT_IN_DIRECTORY|NOT_IN_FILES? */
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS);
Packit 90a5c9
    if (err)
Packit 90a5c9
        return err;
Packit 90a5c9
Packit 90a5c9
    if (cmd->path)
Packit 90a5c9
        path = apr_pstrdup(cmd->pool, cmd->path);
Packit 90a5c9
Packit 90a5c9
    while (*arg) {
Packit 90a5c9
        char *val;
Packit 90a5c9
        word = ap_getword_conf(cmd->pool, &arg;;
Packit 90a5c9
        val = strchr(word, '=');
Packit 90a5c9
Packit 90a5c9
        if (!val) {
Packit 90a5c9
            if (!path)
Packit 90a5c9
                path = word;
Packit 90a5c9
            else if (!name)
Packit 90a5c9
                name = word;
Packit 90a5c9
            else {
Packit 90a5c9
                if (cmd->path)
Packit 90a5c9
                    return "BalancerMember can not have a balancer name when defined in a location";
Packit 90a5c9
                else
Packit 90a5c9
                    return "Invalid BalancerMember parameter. Parameter must "
Packit 90a5c9
                           "be in the form 'key=value'";
Packit 90a5c9
            }
Packit 90a5c9
        } else {
Packit 90a5c9
            *val++ = '\0';
Packit 90a5c9
            apr_table_setn(params, word, val);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    if (!path)
Packit 90a5c9
        return "BalancerMember must define balancer name when outside <Proxy > section";
Packit 90a5c9
    if (!name)
Packit 90a5c9
        return "BalancerMember must define remote proxy server";
Packit 90a5c9
Packit 90a5c9
    ap_str_tolower(path);   /* lowercase scheme://hostname */
Packit 90a5c9
Packit 90a5c9
    /* Try to find the balancer */
Packit 90a5c9
    balancer = ap_proxy_get_balancer(cmd->temp_pool, conf, path, 0);
Packit 90a5c9
    if (!balancer) {
Packit 90a5c9
        err = ap_proxy_define_balancer(cmd->pool, &balancer, conf, path, "/", 0);
Packit 90a5c9
        if (err)
Packit 90a5c9
            return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Try to find existing worker */
Packit 90a5c9
    worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
Packit 90a5c9
    if (!worker) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147)
Packit 90a5c9
                     "Defining worker '%s' for balancer '%s'",
Packit 90a5c9
                     name, balancer->s->name);
Packit 90a5c9
        if ((err = ap_proxy_define_worker(cmd->pool, &worker, balancer, conf, name, 0)) != NULL)
Packit 90a5c9
            return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01148)
Packit 90a5c9
                     "Defined worker '%s' for balancer '%s'",
Packit 90a5c9
                     ap_proxy_worker_name(cmd->pool, worker), balancer->s->name);
Packit 90a5c9
        PROXY_COPY_CONF_PARAMS(worker, conf);
Packit 90a5c9
    } else {
Packit 90a5c9
        reuse = 1;
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01149)
Packit 90a5c9
                     "Sharing worker '%s' instead of creating new worker '%s'",
Packit 90a5c9
                     ap_proxy_worker_name(cmd->pool, worker), name);
Packit 90a5c9
    }
Packit 90a5c9
    if (!worker->section_config) {
Packit 90a5c9
        worker->section_config = balancer->section_config;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    arr = apr_table_elts(params);
Packit 90a5c9
    elts = (const apr_table_entry_t *)arr->elts;
Packit 90a5c9
    for (i = 0; i < arr->nelts; i++) {
Packit 90a5c9
        if (reuse) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01150)
Packit 90a5c9
                         "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing",
Packit 90a5c9
                         elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker));
Packit 90a5c9
        } else {
Packit 90a5c9
            err = set_worker_param(cmd->pool, cmd->server, worker, elts[i].key,
Packit 90a5c9
                                               elts[i].val);
Packit 90a5c9
            if (err)
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *
Packit 90a5c9
    set_proxy_param(cmd_parms *cmd, void *dummy, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s = cmd->server;
Packit 90a5c9
    proxy_server_conf *conf =
Packit 90a5c9
    (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
    char *name = NULL;
Packit 90a5c9
    char *word, *val;
Packit 90a5c9
    proxy_balancer *balancer = NULL;
Packit 90a5c9
    proxy_worker *worker = NULL;
Packit 90a5c9
    int in_proxy_section = 0;
Packit 90a5c9
    /* XXX: Should this be NOT_IN_DIRECTORY|NOT_IN_FILES? */
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS);
Packit 90a5c9
    if (err)
Packit 90a5c9
        return err;
Packit 90a5c9
Packit 90a5c9
    if (cmd->directive->parent &&
Packit 90a5c9
        strncasecmp(cmd->directive->parent->directive,
Packit 90a5c9
                    "
Packit 90a5c9
        const char *pargs = cmd->directive->parent->args;
Packit 90a5c9
        /* Directive inside 
Packit 90a5c9
         * Parent directive arg is the worker/balancer name.
Packit 90a5c9
         */
Packit 90a5c9
        name = ap_getword_conf(cmd->temp_pool, &pargs);
Packit 90a5c9
        if ((word = ap_strchr(name, '>')))
Packit 90a5c9
            *word = '\0';
Packit 90a5c9
        in_proxy_section = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        /* Standard set directive with worker/balancer
Packit 90a5c9
         * name as first param.
Packit 90a5c9
         */
Packit 90a5c9
        name = ap_getword_conf(cmd->temp_pool, &arg;;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (ap_proxy_valid_balancer_name(name, 9)) {
Packit 90a5c9
        balancer = ap_proxy_get_balancer(cmd->pool, conf, name, 0);
Packit 90a5c9
        if (!balancer) {
Packit 90a5c9
            if (in_proxy_section) {
Packit 90a5c9
                err = ap_proxy_define_balancer(cmd->pool, &balancer, conf, name, "/", 0);
Packit 90a5c9
                if (err)
Packit 90a5c9
                    return apr_pstrcat(cmd->temp_pool, "ProxySet ",
Packit 90a5c9
                                       err, NULL);
Packit 90a5c9
            }
Packit 90a5c9
            else
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, "ProxySet can not find '",
Packit 90a5c9
                                   name, "' Balancer.", NULL);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
Packit 90a5c9
        if (!worker) {
Packit 90a5c9
            if (in_proxy_section) {
Packit 90a5c9
                err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
Packit 90a5c9
                                             conf, name, 0);
Packit 90a5c9
                if (err)
Packit 90a5c9
                    return apr_pstrcat(cmd->temp_pool, "ProxySet ",
Packit 90a5c9
                                       err, NULL);
Packit 90a5c9
            }
Packit 90a5c9
            else
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, "ProxySet can not find '",
Packit 90a5c9
                                   name, "' Worker.", NULL);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    while (*arg) {
Packit 90a5c9
        word = ap_getword_conf(cmd->pool, &arg;;
Packit 90a5c9
        val = strchr(word, '=');
Packit 90a5c9
        if (!val) {
Packit 90a5c9
            return "Invalid ProxySet parameter. Parameter must be "
Packit 90a5c9
                   "in the form 'key=value'";
Packit 90a5c9
        }
Packit 90a5c9
        else
Packit 90a5c9
            *val++ = '\0';
Packit 90a5c9
        if (worker)
Packit 90a5c9
            err = set_worker_param(cmd->pool, cmd->server, worker, word, val);
Packit 90a5c9
        else
Packit 90a5c9
            err = set_balancer_param(conf, cmd->pool, balancer, word, val);
Packit 90a5c9
Packit 90a5c9
        if (err)
Packit 90a5c9
            return apr_pstrcat(cmd->temp_pool, "ProxySet: ", err, " ", word, "=", val, "; ", name, NULL);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
Packit 90a5c9
{
Packit 90a5c9
    proxy_server_conf *sconf = ap_get_module_config(s->module_config,
Packit 90a5c9
                                                    &proxy_module);
Packit 90a5c9
    void **new_space = (void **)apr_array_push(sconf->sec_proxy);
Packit 90a5c9
Packit 90a5c9
    *new_space = dir_config;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    const char *errmsg;
Packit 90a5c9
    const char *endp = ap_strrchr_c(arg, '>');
Packit 90a5c9
    int old_overrides = cmd->override;
Packit 90a5c9
    char *old_path = cmd->path;
Packit 90a5c9
    proxy_dir_conf *conf;
Packit 90a5c9
    ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
Packit 90a5c9
    ap_regex_t *r = NULL;
Packit 90a5c9
    const command_rec *thiscmd = cmd->cmd;
Packit 90a5c9
    char *word, *val;
Packit 90a5c9
    proxy_balancer *balancer = NULL;
Packit 90a5c9
    proxy_worker *worker = NULL;
Packit 90a5c9
Packit 90a5c9
    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT);
Packit 90a5c9
    proxy_server_conf *sconf =
Packit 90a5c9
    (proxy_server_conf *) ap_get_module_config(cmd->server->module_config, &proxy_module);
Packit 90a5c9
Packit 90a5c9
    if (err != NULL) {
Packit 90a5c9
        return err;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (endp == NULL) {
Packit 90a5c9
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
Packit 90a5c9
                           "> directive missing closing '>'", NULL);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    arg = apr_pstrndup(cmd->pool, arg, endp-arg);
Packit 90a5c9
Packit 90a5c9
    if (!arg) {
Packit 90a5c9
        if (thiscmd->cmd_data)
Packit 90a5c9
            return "<ProxyMatch > block must specify a path";
Packit 90a5c9
        else
Packit 90a5c9
            return "<Proxy > block must specify a path";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    cmd->path = ap_getword_conf(cmd->pool, &arg;;
Packit 90a5c9
    cmd->override = OR_ALL|ACCESS_CONF|PROXY_CONF;
Packit 90a5c9
Packit 90a5c9
    if (!strncasecmp(cmd->path, "proxy:", 6))
Packit 90a5c9
        cmd->path += 6;
Packit 90a5c9
Packit 90a5c9
    /* XXX Ignore case?  What if we proxy a case-insensitive server?!?
Packit 90a5c9
     * While we are at it, shouldn't we also canonicalize the entire
Packit 90a5c9
     * scheme?  See proxy_fixup()
Packit 90a5c9
     */
Packit 90a5c9
    if (thiscmd->cmd_data) { /* <ProxyMatch> */
Packit 90a5c9
        r = ap_pregcomp(cmd->pool, cmd->path, AP_REG_EXTENDED);
Packit 90a5c9
        if (!r) {
Packit 90a5c9
            return "Regex could not be compiled";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* initialize our config and fetch it */
Packit 90a5c9
    conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
Packit 90a5c9
                                 &proxy_module, cmd->pool);
Packit 90a5c9
Packit 90a5c9
    errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
Packit 90a5c9
    if (errmsg != NULL)
Packit 90a5c9
        return errmsg;
Packit 90a5c9
Packit 90a5c9
    conf->r = r;
Packit 90a5c9
    conf->p = cmd->path;
Packit 90a5c9
    conf->p_is_fnmatch = apr_fnmatch_test(conf->p);
Packit 90a5c9
Packit 90a5c9
    if (r) {
Packit 90a5c9
        conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
Packit 90a5c9
        ap_regname(r, conf->refs, AP_REG_MATCH, 1);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ap_add_per_proxy_conf(cmd->server, new_dir_conf);
Packit 90a5c9
Packit 90a5c9
    if (*arg != '\0') {
Packit 90a5c9
        if (thiscmd->cmd_data)
Packit 90a5c9
            return "Multiple <ProxyMatch> arguments not (yet) supported.";
Packit 90a5c9
        if (conf->p_is_fnmatch)
Packit 90a5c9
            return apr_pstrcat(cmd->pool, thiscmd->name,
Packit 90a5c9
                               "> arguments are not supported for wildchar url.",
Packit 90a5c9
                               NULL);
Packit 90a5c9
        if (!ap_strchr_c(conf->p, ':'))
Packit 90a5c9
            return apr_pstrcat(cmd->pool, thiscmd->name,
Packit 90a5c9
                               "> arguments are not supported for non url.",
Packit 90a5c9
                               NULL);
Packit 90a5c9
        if (ap_proxy_valid_balancer_name((char *)conf->p, 9)) {
Packit 90a5c9
            balancer = ap_proxy_get_balancer(cmd->pool, sconf, conf->p, 0);
Packit 90a5c9
            if (!balancer) {
Packit 90a5c9
                err = ap_proxy_define_balancer(cmd->pool, &balancer,
Packit 90a5c9
                                               sconf, conf->p, "/", 0);
Packit 90a5c9
                if (err)
Packit 90a5c9
                    return apr_pstrcat(cmd->temp_pool, thiscmd->name,
Packit 90a5c9
                                       " ", err, NULL);
Packit 90a5c9
            }
Packit 90a5c9
            if (!balancer->section_config) {
Packit 90a5c9
                balancer->section_config = new_dir_conf;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf,
Packit 90a5c9
                                         ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p));
Packit 90a5c9
            if (!worker) {
Packit 90a5c9
                err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
Packit 90a5c9
                                          sconf, conf->p, 0);
Packit 90a5c9
                if (err)
Packit 90a5c9
                    return apr_pstrcat(cmd->temp_pool, thiscmd->name,
Packit 90a5c9
                                       " ", err, NULL);
Packit 90a5c9
            }
Packit 90a5c9
            if (!worker->section_config) {
Packit 90a5c9
                worker->section_config = new_dir_conf;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        if (worker == NULL && balancer == NULL) {
Packit 90a5c9
            return apr_pstrcat(cmd->pool, thiscmd->name,
Packit 90a5c9
                               "> arguments are supported only for workers.",
Packit 90a5c9
                               NULL);
Packit 90a5c9
        }
Packit 90a5c9
        while (*arg) {
Packit 90a5c9
            word = ap_getword_conf(cmd->pool, &arg;;
Packit 90a5c9
            val = strchr(word, '=');
Packit 90a5c9
            if (!val) {
Packit 90a5c9
                return "Invalid Proxy parameter. Parameter must be "
Packit 90a5c9
                       "in the form 'key=value'";
Packit 90a5c9
            }
Packit 90a5c9
            else
Packit 90a5c9
                *val++ = '\0';
Packit 90a5c9
            if (worker)
Packit 90a5c9
                err = set_worker_param(cmd->pool, cmd->server, worker, word, val);
Packit 90a5c9
            else
Packit 90a5c9
                err = set_balancer_param(sconf, cmd->pool, balancer,
Packit 90a5c9
                                         word, val);
Packit 90a5c9
            if (err)
Packit 90a5c9
                return apr_pstrcat(cmd->temp_pool, thiscmd->name, " ", err, " ",
Packit 90a5c9
                                   word, "=", val, "; ", conf->p, NULL);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    cmd->path = old_path;
Packit 90a5c9
    cmd->override = old_overrides;
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const command_rec proxy_cmds[] =
Packit 90a5c9
{
Packit 90a5c9
    AP_INIT_RAW_ARGS("
Packit 90a5c9
    "Container for directives affecting resources located in the proxied "
Packit 90a5c9
    "location"),
Packit 90a5c9
    AP_INIT_RAW_ARGS("
Packit 90a5c9
    "Container for directives affecting resources located in the proxied "
Packit 90a5c9
    "location, in regular expression syntax"),
Packit 90a5c9
    AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
Packit 90a5c9
     "on if the true proxy requests should be accepted"),
Packit 90a5c9
    AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
Packit 90a5c9
     "a scheme, partial URL or '*' and a proxy server"),
Packit 90a5c9
    AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
Packit 90a5c9
     "a regex pattern and a proxy server"),
Packit 90a5c9
    AP_INIT_FLAG("ProxyPassInterpolateEnv", ap_set_flag_slot_char,
Packit 90a5c9
        (void*)APR_OFFSETOF(proxy_dir_conf, interpolate_env),
Packit 90a5c9
        RSRC_CONF|ACCESS_CONF, "Interpolate Env Vars in reverse Proxy") ,
Packit 90a5c9
    AP_INIT_RAW_ARGS("ProxyPass", add_pass_noregex, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "a virtual path and a URL"),
Packit 90a5c9
    AP_INIT_RAW_ARGS("ProxyPassMatch", add_pass_regex, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "a virtual path and a URL"),
Packit 90a5c9
    AP_INIT_TAKE123("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "a virtual path and a URL for reverse proxy behaviour"),
Packit 90a5c9
    AP_INIT_TAKE23("ProxyPassReverseCookiePath", cookie_path, NULL,
Packit 90a5c9
       RSRC_CONF|ACCESS_CONF, "Path rewrite rule for proxying cookies"),
Packit 90a5c9
    AP_INIT_TAKE23("ProxyPassReverseCookieDomain", cookie_domain, NULL,
Packit 90a5c9
       RSRC_CONF|ACCESS_CONF, "Domain rewrite rule for proxying cookies"),
Packit 90a5c9
    AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF,
Packit 90a5c9
     "A list of names, hosts or domains to which the proxy will not connect"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF,
Packit 90a5c9
     "Receive buffer size for outgoing HTTP and FTP connections in bytes"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyIOBufferSize", set_io_buffer_size, NULL, RSRC_CONF,
Packit 90a5c9
     "IO buffer size for outgoing HTTP and FTP connections in bytes"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyMaxForwards", set_max_forwards, NULL, RSRC_CONF,
Packit 90a5c9
     "The maximum number of proxies a request may be forwarded through."),
Packit 90a5c9
    AP_INIT_ITERATE("NoProxy", set_proxy_dirconn, NULL, RSRC_CONF,
Packit 90a5c9
     "A list of domains, hosts, or subnets to which the proxy will connect directly"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyDomain", set_proxy_domain, NULL, RSRC_CONF,
Packit 90a5c9
     "The default intranet domain name (in absence of a domain in the URL)"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF,
Packit 90a5c9
     "Configure Via: proxy header header to one of: on | off | block | full"),
Packit 90a5c9
    AP_INIT_FLAG("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "use our error handling pages instead of the servers' we are proxying"),
Packit 90a5c9
    AP_INIT_FLAG("ProxyPreserveHost", set_preserve_host, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "on if we should preserve host header while proxying"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyTimeout", set_proxy_timeout, NULL, RSRC_CONF,
Packit 90a5c9
     "Set the timeout (in seconds) for a proxied connection. "
Packit 90a5c9
     "This overrides the server timeout"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
Packit 90a5c9
     "How to handle bad header line in response: IsError | Ignore | StartBody"),
Packit 90a5c9
    AP_INIT_RAW_ARGS("BalancerMember", add_member, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "A balancer name and scheme with list of params"),
Packit 90a5c9
    AP_INIT_TAKE1("BalancerGrowth", set_bgrowth, NULL, RSRC_CONF,
Packit 90a5c9
     "Number of additional Balancers that can be added post-config"),
Packit 90a5c9
    AP_INIT_FLAG("BalancerPersist", set_persist, NULL, RSRC_CONF,
Packit 90a5c9
     "on if the balancer should persist changes on reboot/restart made via the Balancer Manager"),
Packit 90a5c9
    AP_INIT_FLAG("BalancerInherit", set_inherit, NULL, RSRC_CONF,
Packit 90a5c9
     "on if this server should inherit Balancers and Workers defined in the main server "
Packit 90a5c9
     "(Setting to off recommended if using the Balancer Manager)"),
Packit 90a5c9
    AP_INIT_FLAG("ProxyPassInherit", set_ppinherit, NULL, RSRC_CONF,
Packit 90a5c9
     "on if this server should inherit all ProxyPass directives defined in the main server "
Packit 90a5c9
     "(Setting to off recommended if using the Balancer Manager)"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxyStatus", set_status_opt, NULL, RSRC_CONF,
Packit 90a5c9
     "Configure Status: proxy status to one of: on | off | full"),
Packit 90a5c9
    AP_INIT_RAW_ARGS("ProxySet", set_proxy_param, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "A balancer or worker name with list of params"),
Packit 90a5c9
    AP_INIT_TAKE1("ProxySourceAddress", set_source_address, NULL, RSRC_CONF,
Packit 90a5c9
     "Configure local source IP used for request forward"),
Packit 90a5c9
    AP_INIT_FLAG("ProxyAddHeaders", add_proxy_http_headers, NULL, RSRC_CONF|ACCESS_CONF,
Packit 90a5c9
     "on if X-Forwarded-* headers should be added or completed"),
Packit f02de7
    AP_INIT_FLAG("Proxy100Continue", forward_100_continue, NULL, RSRC_CONF|ACCESS_CONF,
Packit f02de7
     "on if 100-Continue should be forwarded to the origin server, off if the "
Packit f02de7
     "proxy should handle it by itself"),
Packit 90a5c9
    {NULL}
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = NULL;
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable = NULL;
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *proxy_ssl_engine = NULL;
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *proxy_is_https = NULL;
Packit 90a5c9
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *proxy_ssl_val = NULL;
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c)
Packit 90a5c9
{
Packit 90a5c9
    /*
Packit 90a5c9
     * if c == NULL just check if the optional function was imported
Packit 90a5c9
     * else run the optional function so ssl filters are inserted
Packit 90a5c9
     */
Packit 90a5c9
    if (proxy_ssl_enable) {
Packit 90a5c9
        return c ? proxy_ssl_enable(c) : 1;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c)
Packit 90a5c9
{
Packit 90a5c9
    if (proxy_ssl_disable) {
Packit 90a5c9
        return proxy_ssl_disable(c);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(int) ap_proxy_ssl_engine(conn_rec *c,
Packit 90a5c9
                                       ap_conf_vector_t *per_dir_config,
Packit 90a5c9
                                       int enable)
Packit 90a5c9
{
Packit 90a5c9
    /*
Packit 90a5c9
     * if c == NULL just check if the optional function was imported
Packit 90a5c9
     * else run the optional function so ssl filters are inserted
Packit 90a5c9
     */
Packit 90a5c9
    if (proxy_ssl_engine) {
Packit 90a5c9
        return c ? proxy_ssl_engine(c, per_dir_config, 1, enable) : 1;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!per_dir_config) {
Packit 90a5c9
        if (enable) {
Packit 90a5c9
            return ap_proxy_ssl_enable(c);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            return ap_proxy_ssl_disable(c);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(int) ap_proxy_conn_is_https(conn_rec *c)
Packit 90a5c9
{
Packit 90a5c9
    if (proxy_is_https) {
Packit 90a5c9
        return proxy_is_https(c);
Packit 90a5c9
    }
Packit 90a5c9
    else
Packit 90a5c9
        return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
PROXY_DECLARE(const char *) ap_proxy_ssl_val(apr_pool_t *p, server_rec *s,
Packit 90a5c9
                                             conn_rec *c, request_rec *r,
Packit 90a5c9
                                             const char *var)
Packit 90a5c9
{
Packit 90a5c9
    if (proxy_ssl_val) {
Packit 90a5c9
        /* XXX Perhaps the casting useless */
Packit 90a5c9
        return (const char *)proxy_ssl_val(p, s, c, r, (char *)var);
Packit 90a5c9
    }
Packit 90a5c9
    else
Packit 90a5c9
        return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog,
Packit 90a5c9
                             apr_pool_t *ptemp, server_rec *main_s)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s = main_s;
Packit 90a5c9
    apr_status_t rv = ap_global_mutex_create(&proxy_mutex, NULL,
Packit 90a5c9
                                             proxy_id, NULL, s, pconf, 0);
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(02478)
Packit 90a5c9
        "failed to create %s mutex", proxy_id);
Packit 90a5c9
        return rv;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
Packit 90a5c9
    proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
Packit 90a5c9
    proxy_ssl_engine = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set);
Packit 90a5c9
    proxy_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
Packit 90a5c9
    proxy_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
Packit 90a5c9
    ap_proxy_strmatch_path = apr_strmatch_precompile(pconf, "path=", 0);
Packit 90a5c9
    ap_proxy_strmatch_domain = apr_strmatch_precompile(pconf, "domain=", 0);
Packit 90a5c9
Packit 90a5c9
    for (; s; s = s->next) {
Packit 90a5c9
        int rc, i;
Packit 90a5c9
        proxy_server_conf *sconf =
Packit 90a5c9
            ap_get_module_config(s->module_config, &proxy_module);
Packit 90a5c9
        ap_conf_vector_t **sections =
Packit 90a5c9
            (ap_conf_vector_t **)sconf->sec_proxy->elts;
Packit 90a5c9
Packit 90a5c9
        for (i = 0; i < sconf->sec_proxy->nelts; ++i) {
Packit 90a5c9
            rc = proxy_run_section_post_config(pconf, ptemp, plog,
Packit 90a5c9
                                               s, sections[i]);
Packit 90a5c9
            if (rc != OK && rc != DECLINED) {
Packit 90a5c9
                return rc;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 *  proxy Extension to mod_status
Packit 90a5c9
 */
Packit 90a5c9
static int proxy_status_hook(request_rec *r, int flags)
Packit 90a5c9
{
Packit 90a5c9
    int i, n;
Packit 90a5c9
    void *sconf = r->server->module_config;
Packit 90a5c9
    proxy_server_conf *conf = (proxy_server_conf *)
Packit 90a5c9
        ap_get_module_config(sconf, &proxy_module);
Packit 90a5c9
    proxy_balancer *balancer = NULL;
Packit 90a5c9
    proxy_worker **worker = NULL;
Packit 90a5c9
Packit 90a5c9
    if (conf->balancers->nelts == 0 ||
Packit 90a5c9
        conf->proxy_status == status_off)
Packit 90a5c9
        return OK;
Packit 90a5c9
Packit 90a5c9
    balancer = (proxy_balancer *)conf->balancers->elts;
Packit 90a5c9
    for (i = 0; i < conf->balancers->nelts; i++) {
Packit 90a5c9
        if (!(flags & AP_STATUS_SHORT)) {
Packit 90a5c9
            ap_rputs("
\n

Proxy LoadBalancer Status for ", r);

Packit 90a5c9
            ap_rvputs(r, balancer->s->name, "\n\n", NULL);
Packit 90a5c9
            ap_rputs("\n\n"
Packit 90a5c9
                     "SSesTimeoutMethod"
Packit 90a5c9
                     "\n", r);
Packit 90a5c9
            if (*balancer->s->sticky) {
Packit 90a5c9
                if (strcmp(balancer->s->sticky, balancer->s->sticky_path)) {
Packit 90a5c9
                    ap_rvputs(r, "", balancer->s->sticky, " | ",
Packit 90a5c9
                              balancer->s->sticky_path, NULL);
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    ap_rvputs(r, "", balancer->s->sticky, NULL);
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                ap_rputs(" - ", r);
Packit 90a5c9
            }
Packit 90a5c9
            ap_rprintf(r, "%" APR_TIME_T_FMT "",
Packit 90a5c9
                       apr_time_sec(balancer->s->timeout));
Packit 90a5c9
            ap_rprintf(r, "%s\n",
Packit 90a5c9
                       balancer->lbmethod->name);
Packit 90a5c9
            ap_rputs("\n", r);
Packit 90a5c9
            ap_rputs("\n\n"
Packit 90a5c9
                     "SchHostStat"
Packit 90a5c9
                     "RouteRedir"
Packit 90a5c9
                     "FSetAccBusyWrRd"
Packit 90a5c9
                     "\n", r);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ap_rprintf(r, "ProxyBalancer[%d]Name: %s\n", i, balancer->s->name);
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        worker = (proxy_worker **)balancer->workers->elts;
Packit 90a5c9
        for (n = 0; n < balancer->workers->nelts; n++) {
Packit 90a5c9
            char fbuf[50];
Packit 90a5c9
            if (!(flags & AP_STATUS_SHORT)) {
Packit 90a5c9
                ap_rvputs(r, "\n", (*worker)->s->scheme, "", NULL);
Packit 90a5c9
                ap_rvputs(r, "", (*worker)->s->hostname_ex, "", NULL);
Packit 90a5c9
                ap_rvputs(r, ap_proxy_parse_wstatus(r->pool, *worker), NULL);
Packit 90a5c9
                ap_rvputs(r, "", (*worker)->s->route, NULL);
Packit 90a5c9
                ap_rvputs(r, "", (*worker)->s->redirect, NULL);
Packit 90a5c9
                ap_rprintf(r, "%.2f", (float)((*worker)->s->lbfactor)/100.0);
Packit 90a5c9
                ap_rprintf(r, "%d", (*worker)->s->lbset);
Packit 90a5c9
                ap_rprintf(r, "%" APR_SIZE_T_FMT "",
Packit 90a5c9
                           (*worker)->s->elected);
Packit 90a5c9
                ap_rprintf(r, "%" APR_SIZE_T_FMT "",
Packit 90a5c9
                           (*worker)->s->busy);
Packit 90a5c9
                ap_rputs(apr_strfsize((*worker)->s->transferred, fbuf), r);
Packit 90a5c9
                ap_rputs("", r);
Packit 90a5c9
                ap_rputs(apr_strfsize((*worker)->s->read, fbuf), r);
Packit 90a5c9
                ap_rputs("\n", r);
Packit 90a5c9
Packit 90a5c9
                /* TODO: Add the rest of dynamic worker data */
Packit 90a5c9
                ap_rputs("\n", r);
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                ap_rprintf(r, "ProxyBalancer[%d]Worker[%d]Name: %s\n",
Packit 90a5c9
                           i, n, (*worker)->s->name);
Packit 90a5c9
                ap_rprintf(r, "ProxyBalancer[%d]Worker[%d]Status: %s\n",
Packit 90a5c9
                           i, n, ap_proxy_parse_wstatus(r->pool, *worker));
Packit 90a5c9
                ap_rprintf(r, "ProxyBalancer[%d]Worker[%d]Elected: %"
Packit 90a5c9
                              APR_SIZE_T_FMT "\n",
Packit 90a5c9
                           i, n, (*worker)->s->elected);
Packit 90a5c9
                ap_rprintf(r, "ProxyBalancer[%d]Worker[%d]Busy: %"
Packit 90a5c9
                              APR_SIZE_T_FMT "\n",
Packit 90a5c9
                           i, n, (*worker)->s->busy);
Packit 90a5c9
                ap_rprintf(r, "ProxyBalancer[%d]Worker[%d]Sent: %"
Packit 90a5c9
                              APR_OFF_T_FMT "K\n",
Packit 90a5c9
                           i, n, (*worker)->s->transferred >> 10);
Packit 90a5c9
                ap_rprintf(r, "ProxyBalancer[%d]Worker[%d]Rcvd: %"
Packit 90a5c9
                              APR_OFF_T_FMT "K\n",
Packit 90a5c9
                           i, n, (*worker)->s->read >> 10);
Packit 90a5c9
Packit 90a5c9
                /* TODO: Add the rest of dynamic worker data */
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            ++worker;
Packit 90a5c9
        }
Packit 90a5c9
        if (!(flags & AP_STATUS_SHORT)) {
Packit 90a5c9
            ap_rputs("\n", r);
Packit 90a5c9
        }
Packit 90a5c9
        ++balancer;
Packit 90a5c9
    }
Packit 90a5c9
    if (!(flags & AP_STATUS_SHORT)) {
Packit 90a5c9
        ap_rputs("
\n"
Packit 90a5c9
                 "SSesSticky session name\n"
Packit 90a5c9
                 "TimeoutBalancer Timeout\n"
Packit 90a5c9
                 "SchConnection scheme\n"
Packit 90a5c9
                 "HostBackend Hostname\n"
Packit 90a5c9
                 "StatWorker status\n"
Packit 90a5c9
                 "RouteSession Route\n"
Packit 90a5c9
                 "RedirSession Route Redirection\n"
Packit 90a5c9
                 "FLoad Balancer Factor\n"
Packit 90a5c9
                 "AccNumber of uses\n"
Packit 90a5c9
                 "WrNumber of bytes transferred\n"
Packit 90a5c9
                 "RdNumber of bytes read\n"
Packit 90a5c9
                 "", r);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void child_init(apr_pool_t *p, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    proxy_worker *reverse = NULL;
Packit 90a5c9
Packit 90a5c9
    apr_status_t rv = apr_global_mutex_child_init(&proxy_mutex,
Packit 90a5c9
                                      apr_global_mutex_lockfile(proxy_mutex),
Packit 90a5c9
                                      p);
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(02479)
Packit 90a5c9
                     "could not init proxy_mutex in child");
Packit 90a5c9
        exit(1); /* Ugly, but what else? */
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* TODO */
Packit 90a5c9
    while (s) {
Packit 90a5c9
        void *sconf = s->module_config;
Packit 90a5c9
        proxy_server_conf *conf;
Packit 90a5c9
        proxy_worker *worker;
Packit 90a5c9
        int i;
Packit 90a5c9
Packit 90a5c9
        conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
Packit 90a5c9
        /*
Packit 90a5c9
         * NOTE: non-balancer members don't use shm at all...
Packit 90a5c9
         *       after all, why should they?
Packit 90a5c9
         */
Packit 90a5c9
        worker = (proxy_worker *)conf->workers->elts;
Packit 90a5c9
        for (i = 0; i < conf->workers->nelts; i++, worker++) {
Packit 90a5c9
            ap_proxy_initialize_worker(worker, s, conf->pool);
Packit 90a5c9
        }
Packit 90a5c9
        /* Create and initialize forward worker if defined */
Packit 90a5c9
        if (conf->req_set && conf->req) {
Packit 90a5c9
            proxy_worker *forward;
Packit 90a5c9
            ap_proxy_define_worker(p, &forward, NULL, NULL, "http://www.apache.org", 0);
Packit 90a5c9
            conf->forward = forward;
Packit 90a5c9
            PROXY_STRNCPY(conf->forward->s->name,     "proxy:forward");
Packit 90a5c9
            PROXY_STRNCPY(conf->forward->s->hostname, "*"); /* for compatibility */
Packit 90a5c9
            PROXY_STRNCPY(conf->forward->s->hostname_ex, "*");
Packit 90a5c9
            PROXY_STRNCPY(conf->forward->s->scheme,   "*");
Packit 90a5c9
            conf->forward->hash.def = conf->forward->s->hash.def =
Packit 90a5c9
                ap_proxy_hashfunc(conf->forward->s->name, PROXY_HASHFUNC_DEFAULT);
Packit 90a5c9
             conf->forward->hash.fnv = conf->forward->s->hash.fnv =
Packit 90a5c9
                ap_proxy_hashfunc(conf->forward->s->name, PROXY_HASHFUNC_FNV);
Packit 90a5c9
            /* Do not disable worker in case of errors */
Packit 90a5c9
            conf->forward->s->status |= PROXY_WORKER_IGNORE_ERRORS;
Packit 90a5c9
            /* Mark as the "generic" worker */
Packit 90a5c9
            conf->forward->s->status |= PROXY_WORKER_GENERIC;
Packit 90a5c9
            ap_proxy_initialize_worker(conf->forward, s, conf->pool);
Packit 90a5c9
            /* Disable address cache for generic forward worker */
Packit 90a5c9
            conf->forward->s->is_address_reusable = 0;
Packit 90a5c9
        }
Packit 90a5c9
        if (!reverse) {
Packit 90a5c9
            ap_proxy_define_worker(p, &reverse, NULL, NULL, "http://www.apache.org", 0);
Packit 90a5c9
            PROXY_STRNCPY(reverse->s->name,     "proxy:reverse");
Packit 90a5c9
            PROXY_STRNCPY(reverse->s->hostname, "*"); /* for compatibility */
Packit 90a5c9
            PROXY_STRNCPY(reverse->s->hostname_ex, "*");
Packit 90a5c9
            PROXY_STRNCPY(reverse->s->scheme,   "*");
Packit 90a5c9
            reverse->hash.def = reverse->s->hash.def =
Packit 90a5c9
                ap_proxy_hashfunc(reverse->s->name, PROXY_HASHFUNC_DEFAULT);
Packit 90a5c9
            reverse->hash.fnv = reverse->s->hash.fnv =
Packit 90a5c9
                ap_proxy_hashfunc(reverse->s->name, PROXY_HASHFUNC_FNV);
Packit 90a5c9
            /* Do not disable worker in case of errors */
Packit 90a5c9
            reverse->s->status |= PROXY_WORKER_IGNORE_ERRORS;
Packit 90a5c9
            /* Mark as the "generic" worker */
Packit 90a5c9
            reverse->s->status |= PROXY_WORKER_GENERIC;
Packit 90a5c9
            conf->reverse = reverse;
Packit 90a5c9
            ap_proxy_initialize_worker(conf->reverse, s, conf->pool);
Packit 90a5c9
            /* Disable address cache for generic reverse worker */
Packit 90a5c9
            reverse->s->is_address_reusable = 0;
Packit 90a5c9
        }
Packit 90a5c9
        conf->reverse = reverse;
Packit 90a5c9
        s = s->next;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * This routine is called before the server processes the configuration
Packit 90a5c9
 * files.
Packit 90a5c9
 */
Packit 90a5c9
static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
Packit 90a5c9
                            apr_pool_t *ptemp)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rv = ap_mutex_register(pconf, proxy_id, NULL,
Packit 90a5c9
            APR_LOCK_DEFAULT, 0);
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(02480)
Packit 90a5c9
                "failed to register %s mutex", proxy_id);
Packit 90a5c9
        return 500; /* An HTTP status would be a misnomer! */
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    APR_OPTIONAL_HOOK(ap, status_hook, proxy_status_hook, NULL, NULL,
Packit 90a5c9
                      APR_HOOK_MIDDLE);
Packit 90a5c9
    /* Reset workers count on gracefull restart */
Packit 90a5c9
    proxy_lb_workers = 0;
Packit 90a5c9
    set_worker_hc_param_f = APR_RETRIEVE_OPTIONAL_FN(set_worker_hc_param);
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
static void register_hooks(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    /* fixup before mod_rewrite, so that the proxied url will not
Packit 90a5c9
     * escaped accidentally by our fixup.
Packit 90a5c9
     */
Packit 90a5c9
    static const char * const aszSucc[] = { "mod_rewrite.c", NULL};
Packit 90a5c9
    /* Only the mpm_winnt has child init hook handler.
Packit 90a5c9
     * make sure that we are called after the mpm
Packit 90a5c9
     * initializes.
Packit 90a5c9
     */
Packit 90a5c9
    static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy_balancer.c",
Packit 90a5c9
                                           "mod_proxy_hcheck.c", NULL};
Packit 90a5c9
    /* handler */
Packit 90a5c9
    ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
Packit 90a5c9
    /* filename-to-URI translation */
Packit 90a5c9
    ap_hook_translate_name(proxy_trans, aszSucc, NULL, APR_HOOK_FIRST);
Packit 90a5c9
    /* walk <Proxy > entries and suppress default TRACE behavior */
Packit 90a5c9
    ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
Packit 90a5c9
    /* fixups */
Packit 90a5c9
    ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST);
Packit 90a5c9
    /* post read_request handling */
Packit 90a5c9
    ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
Packit 90a5c9
    /* pre config handling */
Packit 90a5c9
    ap_hook_pre_config(proxy_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
    /* post config handling */
Packit 90a5c9
    ap_hook_post_config(proxy_post_config, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
    /* child init handling */
Packit 90a5c9
    ap_hook_child_init(child_init, aszPred, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
Packit 90a5c9
    /* register optional functions within proxy_util.c */
Packit 90a5c9
    proxy_util_register_hooks(p);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_MODULE(proxy) =
Packit 90a5c9
{
Packit 90a5c9
    STANDARD20_MODULE_STUFF,
Packit 90a5c9
    create_proxy_dir_config,    /* create per-directory config structure */
Packit 90a5c9
    merge_proxy_dir_config,     /* merge per-directory config structures */
Packit 90a5c9
    create_proxy_config,        /* create per-server config structure */
Packit 90a5c9
    merge_proxy_config,         /* merge per-server config structures */
Packit 90a5c9
    proxy_cmds,                 /* command table */
Packit 90a5c9
    register_hooks
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
APR_HOOK_STRUCT(
Packit 90a5c9
    APR_HOOK_LINK(scheme_handler)
Packit 90a5c9
    APR_HOOK_LINK(canon_handler)
Packit 90a5c9
    APR_HOOK_LINK(pre_request)
Packit 90a5c9
    APR_HOOK_LINK(post_request)
Packit 90a5c9
    APR_HOOK_LINK(request_status)
Packit 90a5c9
)
Packit 90a5c9
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler,
Packit 90a5c9
                                     (request_rec *r, proxy_worker *worker,
Packit 90a5c9
                                      proxy_server_conf *conf,
Packit 90a5c9
                                      char *url, const char *proxyhost,
Packit 90a5c9
                                      apr_port_t proxyport),(r,worker,conf,
Packit 90a5c9
                                      url,proxyhost,proxyport),DECLINED)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, canon_handler,
Packit 90a5c9
                                      (request_rec *r, char *url),(r,
Packit 90a5c9
                                      url),DECLINED)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, pre_request, (
Packit 90a5c9
                                      proxy_worker **worker,
Packit 90a5c9
                                      proxy_balancer **balancer,
Packit 90a5c9
                                      request_rec *r,
Packit 90a5c9
                                      proxy_server_conf *conf,
Packit 90a5c9
                                      char **url),(worker,balancer,
Packit 90a5c9
                                      r,conf,url),DECLINED)
Packit 90a5c9
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, post_request,
Packit 90a5c9
                                      (proxy_worker *worker,
Packit 90a5c9
                                       proxy_balancer *balancer,
Packit 90a5c9
                                       request_rec *r,
Packit 90a5c9
                                       proxy_server_conf *conf),(worker,
Packit 90a5c9
                                       balancer,r,conf),DECLINED)
Packit 90a5c9
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, section_post_config,
Packit 90a5c9
                                    (apr_pool_t *p, apr_pool_t *plog,
Packit 90a5c9
                                     apr_pool_t *ptemp, server_rec *s,
Packit 90a5c9
                                     ap_conf_vector_t *section_config),
Packit 90a5c9
                                    (p, ptemp, plog, s, section_config),
Packit 90a5c9
                                    OK, DECLINED)
Packit 90a5c9
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups,
Packit 90a5c9
                                    (request_rec *r), (r),
Packit 90a5c9
                                    OK, DECLINED)
Packit 90a5c9
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, request_status,
Packit 90a5c9
                                    (int *status, request_rec *r),
Packit 90a5c9
                                    (status, r),
Packit 90a5c9
                                    OK, DECLINED)