-/* ====================================================================
- * The Apache Software License, Version 1.1
+/* Copyright 1999-2004 The Apache Software Foundation
*
- * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
- * reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#define CORE_PRIVATE
#include "mod_proxy.h"
#include "mod_core.h"
-
#include "apr_optional.h"
+#include "scoreboard.h"
+#include "mod_status.h"
+
+#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
+#include "mod_ssl.h"
+#else
+APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
+APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
+#endif
#ifndef MAX
#define MAX(x,y) ((x) >= (y) ? (x) : (y))
/* -------------------------------------------------------------- */
/* Translate the URL into a 'filename' */
+#ifdef FIX_15207
+/* XXX: EBCDIC safe? --nd */
+#define x2c(x) (((x >= '0') && (x <= '9')) \
+ ? (x - '0') \
+ : (((x >= 'a') && (x <= 'f')) \
+ ? (10 + x - 'a') \
+ : ((x >= 'A') && (x <='F')) \
+ ? (10 + x - 'A') \
+ : 0 \
+ ) \
+ )
+
+static unsigned char hex2c(const char* p) {
+ const char c1 = p[1];
+ const char c2 = p[1] ? p[2]: '\0';
+ int i1 = c1 ? x2c(c1) : 0;
+ int i2 = c2 ? x2c(c2) : 0;
+ unsigned char ret = (i1 << 4) | i2;
+
+ return ret;
+}
+#endif
+
+#define PROXY_COPY_CONF_PARAMS(w, c) \
+ do { \
+ (w)->timeout = (c)->timeout; \
+ (w)->timeout_set = (c)->timeout_set; \
+ (w)->recv_buffer_size = (c)->recv_buffer_size; \
+ (w)->recv_buffer_size_set = (c)->recv_buffer_size_set; \
+ (w)->io_buffer_size = (c)->io_buffer_size; \
+ (w)->io_buffer_size_set = (c)->io_buffer_size_set; \
+ } while (0)
+
+static const char *set_worker_param(apr_pool_t *p,
+ proxy_worker *worker,
+ const char *key,
+ const char *val)
+{
+
+ int ival;
+ if (!strcasecmp(key, "loadfactor")) {
+ /* Normalized load factor. Used with BalancerMamber,
+ * it is a number between 1 and 100.
+ */
+ worker->lbfactor = atoi(val);
+ if (worker->lbfactor < 1 || worker->lbfactor > 100)
+ return "LoadFactor must be number between 1..100";
+ }
+ else if (!strcasecmp(key, "retry")) {
+ /* If set it will give the retry timeout for the worker
+ * The default value is 60 seconds, meaning that if
+ * in error state, it will be retried after that timeout.
+ */
+ ival = atoi(val);
+ if (ival < 1)
+ return "Retry must be at least one second";
+ worker->retry = apr_time_from_sec(ival);
+ }
+ else if (!strcasecmp(key, "ttl")) {
+ /* Time in seconds that will destroy all the connections
+ * that exced the smax
+ */
+ ival = atoi(val);
+ if (ival < 1)
+ return "TTL must be at least one second";
+ worker->ttl = apr_time_from_sec(ival);
+ }
+ else if (!strcasecmp(key, "min")) {
+ /* Initial number of connections to remote
+ */
+ ival = atoi(val);
+ if (ival < 0)
+ return "Min must be a positive number";
+ worker->min = ival;
+ }
+ else if (!strcasecmp(key, "max")) {
+ /* Maximum number of connections to remote
+ */
+ ival = atoi(val);
+ if (ival < 0)
+ return "Max must be a positive number";
+ worker->hmax = ival;
+ }
+ /* XXX: More inteligent naming needed */
+ else if (!strcasecmp(key, "smax")) {
+ /* Maximum number of connections to remote that
+ * will not be destroyed
+ */
+ ival = atoi(val);
+ if (ival < 0)
+ return "Smax must be a positive number";
+ worker->smax = ival;
+ }
+ else if (!strcasecmp(key, "acquire")) {
+ /* Acquire timeout in milliseconds.
+ * If set this will be the maximum time to
+ * wait for a free connection.
+ */
+ ival = atoi(val);
+ if (ival < 1)
+ return "Acquire must be at least one mili second";
+ worker->acquire = apr_time_make(0, ival * 1000);
+ worker->acquire_set = 1;
+ }
+ else if (!strcasecmp(key, "timeout")) {
+ /* Connection timeout in seconds.
+ * Defaults to server timeout.
+ */
+ ival = atoi(val);
+ if (ival < 1)
+ return "Timeout must be at least one second";
+ worker->timeout = apr_time_from_sec(ival);
+ worker->timeout_set = 1;
+ }
+ else if (!strcasecmp(key, "iobuffersize")) {
+ long s = atol(val);
+ worker->io_buffer_size = ((s > AP_IOBUFSIZE) ? s : AP_IOBUFSIZE);
+ worker->io_buffer_size_set = 1;
+ }
+ else if (!strcasecmp(key, "receivebuffersize")) {
+ ival = atoi(val);
+ if (ival < 512 && ival != 0) {
+ return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
+ }
+ worker->recv_buffer_size = ival;
+ worker->recv_buffer_size_set = 1;
+ }
+ else if (!strcasecmp(key, "keepalive")) {
+ if (!strcasecmp(val, "on"))
+ worker->keepalive = 1;
+ else if (!strcasecmp(val, "off"))
+ worker->keepalive = 0;
+ else
+ return "KeepAlive must be On|Off";
+ worker->keepalive_set = 1;
+ }
+ else if (!strcasecmp(key, "route")) {
+ /* Worker route.
+ */
+ if (strlen(val) > PROXY_WORKER_MAX_ROUTE_SIZ)
+ return "Route length must be < 64 characters";
+ worker->route = apr_pstrdup(p, val);
+ }
+ else if (!strcasecmp(key, "redirect")) {
+ /* Worker redirection route.
+ */
+ if (strlen(val) > PROXY_WORKER_MAX_ROUTE_SIZ)
+ return "Redirect length must be < 64 characters";
+ worker->redirect = apr_pstrdup(p, val);
+ }
+ else {
+ return "unknown Worker parameter";
+ }
+ return NULL;
+}
+
+static const char *set_balancer_param(apr_pool_t *p,
+ proxy_balancer *balancer,
+ const char *key,
+ const char *val)
+{
+
+ int ival;
+ if (!strcasecmp(key, "stickysession")) {
+ /* Balancer sticky session name.
+ * Set to something like JSESSIONID or
+ * PHPSESSIONID, etc..,
+ */
+ balancer->sticky = apr_pstrdup(p, val);
+ }
+ else if (!strcasecmp(key, "nofailover")) {
+ /* If set to 'on' the session will break
+ * if the worker is in error state or
+ * disabled.
+ */
+ if (!strcasecmp(val, "on"))
+ balancer->sticky_force = 1;
+ else if (!strcasecmp(val, "off"))
+ balancer->sticky_force = 0;
+ else
+ return "failover must be On|Off";
+ }
+ else if (!strcasecmp(key, "timeout")) {
+ /* Balancer timeout in seconds.
+ * If set this will be the maximum time to
+ * wait for a free worker.
+ * Default is not to wait.
+ */
+ ival = atoi(val);
+ if (ival < 1)
+ return "timeout must be at least one second";
+ balancer->timeout = apr_time_from_sec(ival);
+ }
+ else if (!strcasecmp(key, "maxattempts")) {
+ /* Maximum number of failover attempts before
+ * giving up.
+ */
+ ival = atoi(val);
+ if (ival < 0)
+ return "maximum number of attempts must be a positive number";
+ balancer->max_attempts = ival;
+ balancer->max_attempts_set = 1;
+ }
+ else if (!strcasecmp(key, "lbmethod")) {
+ /* Which LB scheduler method */
+ if (!strcasecmp(val, "traffic"))
+ balancer->lbmethod = lbmethod_traffic;
+ else if (!strcasecmp(val, "requests"))
+ balancer->lbmethod = lbmethod_requests;
+ else
+ return "lbmethod must be Traffic|Requests";
+ }
+ else {
+ return "unknown Balancer parameter";
+ }
+ return NULL;
+}
+
static int alias_match(const char *uri, const char *alias_fakename)
{
const char *end_fakename = alias_fakename + strlen(alias_fakename);
const char *aliasp = alias_fakename, *urip = uri;
+ const char *end_uri = uri + strlen(uri);
+ unsigned char uric, aliasc;
- while (aliasp < end_fakename) {
+ while (aliasp < end_fakename && urip < end_uri) {
if (*aliasp == '/') {
/* any number of '/' in the alias matches any number in
* the supplied URI, but there must be at least one...
++urip;
}
else {
+#ifndef FIX_15207
/* Other characters are compared literally */
if (*urip++ != *aliasp++)
return 0;
+#else
+ /* Other characters are canonicalised and compared literally */
+ if (*urip == '%') {
+ uric = hex2c(urip);
+ urip += 3;
+ } else {
+ uric = (unsigned char)*urip++;
+ }
+ if (*aliasp == '%') {
+ aliasc = hex2c(aliasp);
+ aliasp += 3;
+ } else {
+ aliasc = (unsigned char)*aliasp++;
+ }
+ if (uric != aliasc) {
+ return 0;
+ }
+#endif
}
}
- /* Check last alias path component matched all the way */
+ /* fixup badly encoded stuff (e.g. % as last character) */
+ if (aliasp > end_fakename) {
+ aliasp = end_fakename;
+ }
+ if (urip > end_uri) {
+ urip = end_uri;
+ }
+
+ /* We reach the end of the uri before the end of "alias_fakename"
+ * for example uri is "/" and alias_fakename "/examples"
+ */
+ if (urip == end_uri && aliasp!=end_fakename) {
+ return 0;
+ }
+ /* Check last alias path component matched all the way */
if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
return 0;
static int proxy_detect(request_rec *r)
{
void *sconf = r->server->module_config;
- proxy_server_conf *conf;
-
- conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+ proxy_server_conf *conf =
+ (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+#ifdef FIX_15207
+ int i, len;
+ struct proxy_alias *ent = (struct proxy_alias *)conf->aliases->elts;
+#endif
/* Ick... msvc (perhaps others) promotes ternary short results to int */
if (conf->req && r->parsed_uri.scheme) {
/* but it might be something vhosted */
if (!(r->parsed_uri.hostname
- && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
+ && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r))
&& ap_matches_request_vhost(r, r->parsed_uri.hostname,
(apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
: ap_default_port(r))))) {
r->uri = r->unparsed_uri;
r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
r->handler = "proxy-server";
+#ifdef FIX_15207
+ } else {
+ /* test for a ProxyPass */
+ for (i = 0; i < conf->aliases->nelts; i++) {
+ len = alias_match(r->unparsed_uri, ent[i].fake);
+ if (len > 0) {
+ if ((ent[i].real[0] == '!') && (ent[i].real[1] == 0)) {
+ return DECLINED;
+ }
+ r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
+ r->unparsed_uri + len, NULL);
+ r->handler = "proxy-server";
+ r->proxyreq = PROXYREQ_REVERSE;
+ r->uri = r->unparsed_uri;
+ break;
+ }
+ }
+#endif
}
return DECLINED;
}
static int proxy_trans(request_rec *r)
{
+#ifndef FIX_15207
void *sconf = r->server->module_config;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
int i, len;
struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
+#endif
if (r->proxyreq) {
/* someone has already set up the proxy, it was possibly ourselves
return OK;
}
+#ifndef FIX_15207
/* XXX: since r->uri has been manipulated already we're not really
* compliant with RFC1945 at this point. But this probably isn't
* an issue because this is a hybrid proxy/origin server.
len = alias_match(r->uri, ent[i].fake);
if (len > 0) {
- if ((ent[i].real[0] == '!' ) && ( ent[i].real[1] == 0 )) {
+ if ((ent[i].real[0] == '!') && (ent[i].real[1] == 0)) {
return DECLINED;
}
r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
- (r->uri + len ), NULL);
+ r->uri + len, NULL);
r->handler = "proxy-server";
r->proxyreq = PROXYREQ_REVERSE;
return OK;
}
}
+#endif
return DECLINED;
}
return OK;
}
-
+#ifndef FIX_15207
/* -------------------------------------------------------------- */
/* Fixup the filename */
char *url, *p;
int access_status;
- if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
+ if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
return DECLINED;
+#ifdef FIX_15207
+/* We definitely shouldn't canonicalize a proxy_pass.
+ * But should we really canonicalize a STD_PROXY??? -- Fahree
+ */
+ if (r->proxyreq == PROXYREQ_REVERSE) {
+ return OK;
+ }
+#endif
+
/* XXX: Shouldn't we try this before we run the proxy_walk? */
url = &r->filename[6];
if (p == NULL || p == url)
return HTTP_BAD_REQUEST;
- return OK; /* otherwise; we've done the best we can */
+ return OK; /* otherwise; we've done the best we can */
}
-
+#endif
/* Send a redirection if the request contains a hostname which is not */
/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
/* servers like Netscape's allow this and access hosts from the local */
/* If host does contain a dot already, or it is "localhost", decline */
if (strchr(r->parsed_uri.hostname, '.') != NULL
|| strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
- return DECLINED; /* host name has a dot already */
+ return DECLINED; /* host name has a dot already */
ref = apr_table_get(r->headers_in, "Referer");
int direct_connect = 0;
const char *str;
long maxfwd;
+ proxy_balancer *balancer = NULL;
+ proxy_worker *worker = NULL;
+ int attempts = 0, max_attempts = 0;
/* is this for us? */
- if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
+ if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
return DECLINED;
/* handle max-forwards / OPTIONS / TRACE */
apr_table_set(r->headers_in, "Max-Forwards",
apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));
- url = r->filename + 6;
- p = strchr(url, ':');
- if (p == NULL)
- return HTTP_BAD_REQUEST;
-
- /* If the host doesn't have a domain name, add one and redirect. */
- if (conf->domain != NULL) {
- rc = proxy_needsdomain(r, url, conf->domain);
- if (ap_is_HTTP_REDIRECT(rc))
- return HTTP_MOVED_PERMANENTLY;
- }
-
- *p = '\0';
- scheme = apr_pstrdup(r->pool, url);
- *p = ':';
-
- /* Check URI's destination host against NoProxy hosts */
- /* Bypass ProxyRemote server lookup if configured as NoProxy */
- /* we only know how to handle communication to a proxy via http */
- /*if (strcasecmp(scheme, "http") == 0) */
- {
- int ii;
- struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
+ do {
+ url = r->filename + 6;
+ p = strchr(url, ':');
+ if (p == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "proxy_handler no URL in %s", r->filename);
+ return HTTP_BAD_REQUEST;
+ }
- for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
- direct_connect = list[ii].matcher(&list[ii], r);
+ /* If the host doesn't have a domain name, add one and redirect. */
+ if (conf->domain != NULL) {
+ rc = proxy_needsdomain(r, url, conf->domain);
+ if (ap_is_HTTP_REDIRECT(rc))
+ return HTTP_MOVED_PERMANENTLY;
}
+
+ *p = '\0';
+ scheme = apr_pstrdup(r->pool, url);
+ *p = ':';
+
+ /* Check URI's destination host against NoProxy hosts */
+ /* Bypass ProxyRemote server lookup if configured as NoProxy */
+ /* we only know how to handle communication to a proxy via http */
+ /*if (strcasecmp(scheme, "http") == 0) */
+ {
+ int ii;
+ struct dirconn_entry *list = (struct dirconn_entry *)
+ conf->dirconn->elts;
+
+ for (direct_connect = ii = 0; ii < conf->dirconn->nelts &&
+ !direct_connect; ii++) {
+ direct_connect = list[ii].matcher(&list[ii], r);
+ }
#if DEBUGGING
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
(direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
r->uri);
#endif
- }
-
- /* firstly, try a proxy, unless a NoProxy directive is active */
- if (!direct_connect) {
- for (i = 0; i < proxies->nelts; i++) {
- p2 = ap_strchr_c(ents[i].scheme, ':'); /* is it a partial URL? */
- if (strcmp(ents[i].scheme, "*") == 0 ||
- (ents[i].use_regex && ap_regexec(ents[i].regexp, url, 0,NULL, 0)) ||
- (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
- (p2 != NULL &&
- strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
-
- /* handle the scheme */
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "Trying to run scheme_handler against proxy");
- access_status = proxy_run_scheme_handler(r, conf, url, ents[i].hostname, ents[i].port);
-
- /* an error or success */
- if (access_status != DECLINED && access_status != HTTP_BAD_GATEWAY) {
- return access_status;
+ }
+
+ /* Try to obtain the most suitable worker */
+ access_status = ap_proxy_pre_request(&worker, &balancer, r, conf, &url);
+ if (access_status != OK)
+ return access_status;
+ if (balancer && balancer->max_attempts_set && !max_attempts)
+ max_attempts = balancer->max_attempts;
+ /* firstly, try a proxy, unless a NoProxy directive is active */
+ if (!direct_connect) {
+ for (i = 0; i < proxies->nelts; i++) {
+ p2 = ap_strchr_c(ents[i].scheme, ':'); /* is it a partial URL? */
+ if (strcmp(ents[i].scheme, "*") == 0 ||
+ (ents[i].use_regex && ap_regexec(ents[i].regexp, url,
+ 0,NULL, 0)) ||
+ (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
+ (p2 != NULL &&
+ strncasecmp(url, ents[i].scheme,
+ strlen(ents[i].scheme)) == 0)) {
+
+ /* handle the scheme */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "Trying to run scheme_handler against proxy");
+ access_status = proxy_run_scheme_handler(r, worker,
+ conf, url,
+ ents[i].hostname,
+ ents[i].port);
+
+ /* an error or success */
+ if (access_status != DECLINED &&
+ access_status != HTTP_BAD_GATEWAY) {
+ goto cleanup;
+ }
+ /* we failed to talk to the upstream proxy */
}
- /* we failed to talk to the upstream proxy */
}
}
- }
- /* otherwise, try it direct */
- /* N.B. what if we're behind a firewall, where we must use a proxy or
- * give up??
- */
+ /* otherwise, try it direct */
+ /* N.B. what if we're behind a firewall, where we must use a proxy or
+ * give up??
+ */
+
+ /* handle the scheme */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "Running scheme %s handler (attempt %d)",
+ scheme, attempts);
+ if ((access_status = proxy_run_scheme_handler(r, worker, conf,
+ url, NULL, 0)) == OK)
+ break;
+
+ } while (!PROXY_WORKER_IS_USABLE(worker) &&
+ max_attempts > attempts++);
- /* handle the scheme */
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "Trying to run scheme_handler");
- access_status = proxy_run_scheme_handler(r, conf, url, NULL, 0);
if (DECLINED == access_status) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"proxy: No protocol handler was valid for the URL %s. "
"If you are using a DSO version of mod_proxy, make sure "
"the proxy submodules are included in the configuration "
"using LoadModule.", r->uri);
- return HTTP_FORBIDDEN;
+ access_status = HTTP_FORBIDDEN;
+ goto cleanup;
+ }
+cleanup:
+ if (balancer) {
+ int post_status = proxy_run_post_request(worker, balancer, r, conf);
+ if (post_status == DECLINED) {
+ post_status = OK; /* no post_request handler available */
+ /* TODO: reclycle direct worker */
+ }
}
return access_status;
}
ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
ps->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ ps->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ ps->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ ps->cookie_path_str = apr_strmatch_precompile(p, "path=", 0);
+ ps->cookie_domain_str = apr_strmatch_precompile(p, "domain=", 0);
ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
+ ps->workers = apr_array_make(p, 10, sizeof(proxy_worker));
+ ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer));
+ ps->forward = NULL;
+ ps->reverse = NULL;
ps->domain = NULL;
ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
ps->viaopt_set = 0; /* 0 means default */
ps->timeout_set = 0;
ps->badopt = bad_error;
ps->badopt_set = 0;
+ ps->pool = p;
return ps;
}
ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
ps->raliases = apr_array_append(p, base->raliases, overrides->raliases);
+ ps->cookie_paths
+ = apr_array_append(p, base->cookie_paths, overrides->cookie_paths);
+ ps->cookie_domains
+ = apr_array_append(p, base->cookie_domains, overrides->cookie_domains);
+ ps->cookie_path_str = base->cookie_path_str;
+ ps->cookie_domain_str = base->cookie_domain_str;
ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
+ ps->workers = apr_array_append(p, base->workers, overrides->workers);
+ ps->balancers = apr_array_append(p, base->balancers, overrides->balancers);
+ ps->forward = overrides->forward ? overrides->forward : base->forward;
+ ps->reverse = overrides->reverse ? overrides->reverse : base->reverse;
ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
ps->preserve_host = (overrides->preserve_host_set == 0) ? base->preserve_host : overrides->preserve_host;
ps->timeout= (overrides->timeout_set == 0) ? base->timeout : overrides->timeout;
ps->badopt = (overrides->badopt_set == 0) ? base->badopt : overrides->badopt;
-
+ ps->proxy_status = (overrides->proxy_status_set == 0) ? base->proxy_status : overrides->proxy_status;
+ ps->pool = p;
return ps;
}
}
else
if (strchr(f, ':') == NULL)
- ap_str_tolower(f); /* lowercase scheme */
- ap_str_tolower(p + 3); /* lowercase hostname */
+ ap_str_tolower(f); /* lowercase scheme */
+ ap_str_tolower(p + 3); /* lowercase hostname */
if (port == -1) {
port = apr_uri_port_of_scheme(scheme);
}
static const char *
- add_pass(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+ add_pass(cmd_parms *cmd, void *dummy, const char *arg)
{
server_rec *s = cmd->server;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
struct proxy_alias *new;
- if (r!=NULL && cmd->path == NULL ) {
- new = apr_array_push(conf->aliases);
- new->fake = f;
- new->real = r;
- } else if (r==NULL && cmd->path != NULL) {
- new = apr_array_push(conf->aliases);
- new->fake = cmd->path;
- new->real = f;
- } else {
- if ( r== NULL)
- return "ProxyPass needs a path when not defined in a location";
- else
- return "ProxyPass can not have a path when defined in a location";
+ char *f = cmd->path;
+ char *r = NULL;
+ char *word;
+ apr_table_t *params = apr_table_make(cmd->pool, 5);
+ const apr_array_header_t *arr;
+ const apr_table_entry_t *elts;
+ int i;
+
+ while (*arg) {
+ word = ap_getword_conf(cmd->pool, &arg);
+ if (!f)
+ f = word;
+ else if (!r)
+ r = word;
+ else {
+ char *val = strchr(word, '=');
+ if (!val) {
+ if (cmd->path)
+ return "Invalid ProxyPass parameter. Parameter must be "
+ "in the form 'key=value'";
+ else
+ return "ProxyPass can not have a path when defined in a location";
+ }
+ else
+ *val++ = '\0';
+ apr_table_setn(params, word, val);
+ }
+ };
+
+ if (r == NULL)
+ return "ProxyPass needs a path when not defined in a location";
+
+ new = apr_array_push(conf->aliases);
+ new->fake = apr_pstrdup(cmd->pool, f);
+ new->real = apr_pstrdup(cmd->pool, r);
+ if (r[0] == '!' && r[1] == '\0')
+ return NULL;
+
+ arr = apr_table_elts(params);
+ elts = (const apr_table_entry_t *)arr->elts;
+ /* Distinguish the balancer from woker */
+ if (strncasecmp(r, "balancer:", 9) == 0) {
+ proxy_balancer *balancer = ap_proxy_get_balancer(cmd->pool, conf, r);
+ if (!balancer) {
+ const char *err = ap_proxy_add_balancer(&balancer,
+ cmd->pool,
+ conf, r);
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+ }
+ for (i = 0; i < arr->nelts; i++) {
+ const char *err = set_balancer_param(cmd->pool, balancer, elts[i].key,
+ elts[i].val);
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+ }
}
+ else {
+ proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, conf, r);
+ if (!worker) {
+ const char *err = ap_proxy_add_worker(&worker, cmd->pool, conf, r);
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+ }
+ PROXY_COPY_CONF_PARAMS(worker, conf);
- return NULL;
+ for (i = 0; i < arr->nelts; i++) {
+ const char *err = set_worker_param(cmd->pool, worker, elts[i].key,
+ elts[i].val);
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+ }
+ }
+ return NULL;
}
static const char *
return NULL;
}
+static const char*
+ cookie_path(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf;
+ struct proxy_alias *new;
+
+ conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
+ &proxy_module);
+ new = apr_array_push(conf->cookie_paths);
+ new->fake = f;
+ new->real = r;
+
+ return NULL;
+}
+static const char*
+ cookie_domain(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf;
+ struct proxy_alias *new;
+
+ conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
+ &proxy_module);
+ new = apr_array_push(conf->cookie_domains);
+ new->fake = f;
+ new->real = r;
+
+ return NULL;
+}
static const char *
set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg)
New->name = apr_pstrdup(parms->pool, arg);
New->hostaddr = NULL;
- if (ap_proxy_is_ipaddr(New, parms->pool)) {
+ if (ap_proxy_is_ipaddr(New, parms->pool)) {
#if DEBUGGING
- ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
- "Parsed addr %s", inet_ntoa(New->addr));
- ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
- "Parsed mask %s", inet_ntoa(New->mask));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed addr %s", inet_ntoa(New->addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed mask %s", inet_ntoa(New->mask));
#endif
- }
- else if (ap_proxy_is_domainname(New, parms->pool)) {
- ap_str_tolower(New->name);
+ }
+ else if (ap_proxy_is_domainname(New, parms->pool)) {
+ ap_str_tolower(New->name);
#if DEBUGGING
- ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
- "Parsed domain %s", New->name);
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed domain %s", New->name);
#endif
}
else if (ap_proxy_is_hostname(New, parms->pool)) {
psf->req = flag;
psf->req_set = 1;
+
+ if (flag && !psf->forward) {
+ psf->forward = ap_proxy_create_worker(parms->pool);
+ psf->forward->name = "proxy:forward";
+ psf->forward->hostname = "*";
+ psf->forward->scheme = "*";
+ }
return NULL;
}
+
static const char *
set_proxy_error_override(cmd_parms *parms, void *dummy, int flag)
{
return NULL;
}
+static const char*
+ set_status_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ if (strcasecmp(arg, "Off") == 0)
+ psf->proxy_status = status_off;
+ else if (strcasecmp(arg, "On") == 0)
+ psf->proxy_status = status_on;
+ else if (strcasecmp(arg, "Full") == 0)
+ psf->proxy_status = status_full;
+ else {
+ return "ProxyStatus must be one of: "
+ "off | on | block";
+ }
+
+ psf->proxy_status_set = 1;
+ return NULL;
+}
+
+static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf =
+ ap_get_module_config(s->module_config, &proxy_module);
+ proxy_balancer *balancer;
+ proxy_worker *worker;
+ char *path = cmd->path;
+ char *name = NULL;
+ char *word;
+ apr_table_t *params = apr_table_make(cmd->pool, 5);
+ const apr_array_header_t *arr;
+ const apr_table_entry_t *elts;
+ int i;
+
+ if (cmd->path)
+ path = apr_pstrdup(cmd->pool, cmd->path);
+ while (*arg) {
+ word = ap_getword_conf(cmd->pool, &arg);
+ if (!path)
+ path = word;
+ else if (!name)
+ name = word;
+ else {
+ char *val = strchr(word, '=');
+ if (!val)
+ if (cmd->path)
+ return "BalancerMember can not have a balancer name when defined in a location";
+ else
+ return "Invalid BalancerMember parameter. Parameter must "
+ "be in the form 'key=value'";
+ else
+ *val++ = '\0';
+ apr_table_setn(params, word, val);
+ }
+ }
+ if (!path)
+ return "BalancerMember must define balancer name when outside <Proxy > section";
+ if (!name)
+ return "BalancerMember must define remote proxy server";
+
+ ap_str_tolower(path); /* lowercase scheme://hostname */
+ ap_str_tolower(name); /* lowercase scheme://hostname */
+
+ /* Try to find existing worker */
+ worker = ap_proxy_get_worker(cmd->temp_pool, conf, name);
+ if (!worker) {
+ const char *err;
+ if ((err = ap_proxy_add_worker(&worker, cmd->pool, conf, name)) != NULL)
+ return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
+ }
+ PROXY_COPY_CONF_PARAMS(worker, conf);
+
+ arr = apr_table_elts(params);
+ elts = (const apr_table_entry_t *)arr->elts;
+ for (i = 0; i < arr->nelts; i++) {
+ const char *err = set_worker_param(cmd->pool, worker, elts[i].key,
+ elts[i].val);
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
+ }
+ /* Try to find the balancer */
+ balancer = ap_proxy_get_balancer(cmd->temp_pool, conf, path);
+ if (!balancer) {
+ const char *err = ap_proxy_add_balancer(&balancer,
+ cmd->pool,
+ conf, path);
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
+ }
+ /* Add the worker to the load balancer */
+ ap_proxy_add_worker_to_balancer(cmd->pool, balancer, worker);
+ return NULL;
+}
+
+static const char *
+ set_proxy_param(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf =
+ (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
+ char *name = NULL;
+ char *word, *val;
+ proxy_balancer *balancer = NULL;
+ proxy_worker *worker = NULL;
+ const char *err;
+
+ if (cmd->directive->parent &&
+ strncasecmp(cmd->directive->parent->directive,
+ "<Proxy", 6) == 0) {
+ const char *pargs = cmd->directive->parent->args;
+ /* Directive inside <Proxy section
+ * Parent directive arg is the worker/balancer name.
+ */
+ name = ap_getword_conf(cmd->temp_pool, &pargs);
+ if ((word = ap_strchr(name, '>')))
+ *word = '\0';
+ }
+ else {
+ /* Standard set directive with worker/balancer
+ * name as first param.
+ */
+ name = ap_getword_conf(cmd->temp_pool, &arg);
+ }
+
+ if (strncasecmp(name, "balancer:", 9) == 0) {
+ balancer = ap_proxy_get_balancer(cmd->pool, conf, name);
+ if (!balancer) {
+ return apr_pstrcat(cmd->temp_pool, "ProxySet can not find '",
+ name, "' Balancer.", NULL);
+ }
+ }
+ else {
+ worker = ap_proxy_get_worker(cmd->temp_pool, conf, name);
+ if (!worker) {
+ return apr_pstrcat(cmd->temp_pool, "ProxySet can not find '",
+ name, "' Worker.", NULL);
+ }
+ }
+
+ while (*arg) {
+ word = ap_getword_conf(cmd->pool, &arg);
+ val = strchr(word, '=');
+ if (!val) {
+ return "Invalid ProxySet parameter. Parameter must be "
+ "in the form 'key=value'";
+ }
+ else
+ *val++ = '\0';
+ if (worker)
+ err = set_worker_param(cmd->pool, worker, word, val);
+ else
+ err = set_balancer_param(cmd->pool, balancer, word, val);
+
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "ProxySet ", err, " ", word, " ", name, NULL);
+ }
+
+ return NULL;
+}
+
static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
{
proxy_server_conf *sconf = ap_get_module_config(s->module_config,
- &proxy_module);
+ &proxy_module);
void **new_space = (void **)apr_array_push(sconf->sec_proxy);
*new_space = dir_config;
*/
if (thiscmd->cmd_data) { /* <ProxyMatch> */
r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+ if (!r) {
+ return "Regex could not be compiled";
+ }
}
else if (!strcmp(cmd->path, "~")) {
cmd->path = ap_getword_conf(cmd->pool, &arg);
if (strncasecmp(cmd->path, "proxy:", 6))
cmd->path += 6;
r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+ if (!r) {
+ return "Regex could not be compiled";
+ }
}
/* initialize our config and fetch it */
"a scheme, partial URL or '*' and a proxy server"),
AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
"a regex pattern and a proxy server"),
- AP_INIT_TAKE12("ProxyPass", add_pass, NULL, RSRC_CONF|ACCESS_CONF,
+ AP_INIT_RAW_ARGS("ProxyPass", add_pass, NULL, RSRC_CONF|ACCESS_CONF,
"a virtual path and a URL"),
AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF,
"a virtual path and a URL for reverse proxy behaviour"),
+ AP_INIT_TAKE2("ProxyPassReverseCookiePath", cookie_path, NULL,
+ RSRC_CONF|ACCESS_CONF, "Path rewrite rule for proxying cookies"),
+ AP_INIT_TAKE2("ProxyPassReverseCookieDomain", cookie_domain, NULL,
+ RSRC_CONF|ACCESS_CONF, "Domain rewrite rule for proxying cookies"),
AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF,
"A list of names, hosts or domains to which the proxy will not connect"),
AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF,
"This overrides the server timeout"),
AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
"How to handle bad header line in response: IsError | Ignore | StartBody"),
-
+ AP_INIT_RAW_ARGS("BalancerMember", add_member, NULL, RSRC_CONF|ACCESS_CONF,
+ "A balancer name and scheme with list of params"),
+ AP_INIT_TAKE1("ProxyStatus", set_status_opt, NULL, RSRC_CONF,
+ "Configure Status: proxy status to one of: on | off | full"),
+ AP_INIT_RAW_ARGS("ProxySet", set_proxy_param, NULL, RSRC_CONF|ACCESS_CONF,
+ "A balancer or worker name with list of params"),
{NULL}
};
-APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
-APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
-
static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = NULL;
static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable = NULL;
static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
+
proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
return OK;
}
+/*
+ * proxy Extension to mod_status
+ */
+static int proxy_status_hook(request_rec *r, int flags)
+{
+ int i, n;
+ void *sconf = r->server->module_config;
+ proxy_server_conf *conf = (proxy_server_conf *)
+ ap_get_module_config(sconf, &proxy_module);
+ proxy_balancer *balancer = NULL;
+ proxy_worker *worker = NULL;
+
+ if (flags & AP_STATUS_SHORT || conf->balancers->nelts == 0 ||
+ conf->proxy_status == status_off)
+ return OK;
+
+ balancer = (proxy_balancer *)conf->balancers->elts;
+ for (i = 0; i < conf->balancers->nelts; i++) {
+ ap_rputs("<hr />\n<h1>Proxy LoadBalancer Status for ", r);
+ ap_rvputs(r, balancer->name, "</h1>\n\n", NULL);
+ ap_rputs("\n\n<table border=\"0\"><tr>"
+ "<th>SSes</th><th>Timeout</th><th>Method</th>"
+ "</tr>\n<tr>", r);
+ ap_rvputs(r, "<td>", balancer->sticky, NULL);
+ ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
+ apr_time_sec(balancer->timeout));
+ ap_rprintf(r, "<td>%s</td>\n",
+ balancer->lbmethod == lbmethod_requests ? "Requests" :
+ balancer->lbmethod == lbmethod_traffic ? "Traffic" :
+ "Unknown");
+ ap_rputs("</table>\n", r);
+ ap_rputs("\n\n<table border=\"0\"><tr>"
+ "<th>Sch</th><th>Host</th><th>Stat</th>"
+ "<th>Route</th><th>Redir</th>"
+ "<th>F</th><th>Acc</th><th>Wr</th><th>Rd</th>"
+ "</tr>\n", r);
+
+ worker = (proxy_worker *)balancer->workers->elts;
+ for (n = 0; n < balancer->workers->nelts; n++) {
+ char fbuf[50];
+ ap_rvputs(r, "<tr>\n<td>", worker->scheme, "</td>", NULL);
+ ap_rvputs(r, "<td>", worker->hostname, "</td><td>", NULL);
+ if (worker->s->status & PROXY_WORKER_DISABLED)
+ ap_rputs("Dis", r);
+ else if (worker->s->status & PROXY_WORKER_IN_ERROR)
+ ap_rputs("Err", r);
+ else if (worker->s->status & PROXY_WORKER_INITIALIZED)
+ ap_rputs("Ok", r);
+ else
+ ap_rputs("-", r);
+ ap_rvputs(r, "</td><td>", worker->s->route, NULL);
+ ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
+ ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
+ ap_rprintf(r, "<td>%d</td><td>", (int)(worker->s->elected));
+ ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r);
+ ap_rputs("</td><td>", r);
+ ap_rputs(apr_strfsize(worker->s->read, fbuf), r);
+ ap_rputs("</td>\n", r);
+
+ /* TODO: Add the rest of dynamic worker data */
+ ap_rputs("</tr>\n", r);
+
+ ++worker;
+ }
+ ap_rputs("</table>\n", r);
+ ++balancer;
+ }
+ ap_rputs("<hr /><table>\n"
+ "<tr><th>SSes</th><td>Sticky session name</td></tr>\n"
+ "<tr><th>Timeout</th><td>Balancer Timeout</td></tr>\n"
+ "<tr><th>Sch</th><td>Connection scheme</td></tr>\n"
+ "<tr><th>Host</th><td>Backend Hostname</td></tr>\n"
+ "<tr><th>Stat</th><td>Worker status</td></tr>\n"
+ "<tr><th>Route</th><td>Session Route</td></tr>\n"
+ "<tr><th>Redir</th><td>Session Route Redirection</td></tr>\n"
+ "<tr><th>F</th><td>Load Balancer Factor in %</td></tr>\n"
+ "<tr><th>Acc</th><td>Number of requests</td></tr>\n"
+ "<tr><th>Wr</th><td>Number of bytes transferred</td></tr>\n"
+ "<tr><th>Rd</th><td>Number of bytes read</td></tr>\n"
+ "</table>", r);
+
+ return OK;
+}
+
+static void child_init(apr_pool_t *p, server_rec *s)
+{
+ proxy_worker *reverse = NULL;
+
+ while (s) {
+ void *sconf = s->module_config;
+ proxy_server_conf *conf;
+ proxy_worker *worker;
+ int i;
+
+ conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
+ /* Initialize worker's shared scoreboard data */
+ worker = (proxy_worker *)conf->workers->elts;
+ for (i = 0; i < conf->workers->nelts; i++) {
+ ap_proxy_initialize_worker_share(conf, worker, s);
+ ap_proxy_initialize_worker(worker, s);
+ worker++;
+ }
+ /* Initialize forward worker if defined */
+ if (conf->forward) {
+ ap_proxy_initialize_worker_share(conf, conf->forward, s);
+ ap_proxy_initialize_worker(conf->forward, s);
+ /* Do not disable worker in case of errors */
+ conf->forward->s->status |= PROXY_WORKER_IGNORE_ERRORS;
+ /* Disable address cache for generic forward worker */
+ conf->forward->is_address_reusable = 0;
+ }
+ if (!reverse) {
+ reverse = ap_proxy_create_worker(p);
+ reverse->name = "proxy:reverse";
+ reverse->hostname = "*";
+ reverse->scheme = "*";
+ ap_proxy_initialize_worker_share(conf, reverse, s);
+ ap_proxy_initialize_worker(reverse, s);
+ /* Do not disable worker in case of errors */
+ reverse->s->status |= PROXY_WORKER_IGNORE_ERRORS;
+ /* Disable address cache for generic reverse worker */
+ reverse->is_address_reusable = 0;
+ }
+ conf->reverse = reverse;
+ s = s->next;
+ }
+}
+
+/*
+ * This routine is called before the server processes the configuration
+ * files. There is no return value.
+ */
+static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
+ apr_pool_t *ptemp)
+{
+ APR_OPTIONAL_HOOK(ap, status_hook, proxy_status_hook, NULL, NULL,
+ APR_HOOK_MIDDLE);
+ /* Reset workers count on gracefull restart */
+ proxy_lb_workers = 0;
+ return OK;
+}
+
static void register_hooks(apr_pool_t *p)
{
+ /* fixup before mod_rewrite, so that the proxied url will not
+ * escaped accidentally by our fixup.
+ */
+#ifndef FIX_15207
+ static const char * const aszSucc[]={ "mod_rewrite.c", NULL };
+#endif
+ /* Only the mpm_winnt has child init hook handler.
+ * make sure that we are called after the mpm
+ * initializes.
+ */
+ static const char *const aszPred[] = { "mpm_winnt.c", NULL};
+
+ APR_REGISTER_OPTIONAL_FN(ap_proxy_lb_workers);
/* handler */
ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
/* filename-to-URI translation */
ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST);
/* walk <Proxy > entries and suppress default TRACE behavior */
ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
+#ifndef FIX_15207
/* fixups */
- ap_hook_fixups(proxy_fixup, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST);
+#endif
/* post read_request handling */
ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
+ /* pre config handling */
+ ap_hook_pre_config(proxy_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
/* post config handling */
ap_hook_post_config(proxy_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+ /* child init handling */
+ ap_hook_child_init(child_init, aszPred, NULL, APR_HOOK_MIDDLE);
+
}
module AP_MODULE_DECLARE_DATA proxy_module =
STANDARD20_MODULE_STUFF,
create_proxy_dir_config, /* create per-directory config structure */
merge_proxy_dir_config, /* merge per-directory config structures */
- create_proxy_config, /* create per-server config structure */
- merge_proxy_config, /* merge per-server config structures */
- proxy_cmds, /* command table */
+ create_proxy_config, /* create per-server config structure */
+ merge_proxy_config, /* merge per-server config structures */
+ proxy_cmds, /* command table */
register_hooks
};
APR_HOOK_STRUCT(
- APR_HOOK_LINK(scheme_handler)
- APR_HOOK_LINK(canon_handler)
+ APR_HOOK_LINK(scheme_handler)
+ APR_HOOK_LINK(canon_handler)
+ APR_HOOK_LINK(pre_request)
+ APR_HOOK_LINK(post_request)
)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler,
- (request_rec *r, proxy_server_conf *conf,
- char *url, const char *proxyhost,
- apr_port_t proxyport),(r,conf,url,
- proxyhost,proxyport),DECLINED)
+ (request_rec *r, proxy_worker *worker,
+ proxy_server_conf *conf,
+ char *url, const char *proxyhost,
+ apr_port_t proxyport),(r,worker,conf,
+ url,proxyhost,proxyport),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, canon_handler,
- (request_rec *r, char *url),(r,
- url),DECLINED)
+ (request_rec *r, char *url),(r,
+ url),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, pre_request, (
+ proxy_worker **worker,
+ proxy_balancer **balancer,
+ request_rec *r,
+ proxy_server_conf *conf,
+ char **url),(worker,balancer,
+ r,conf,url),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, post_request,
+ (proxy_worker *worker,
+ proxy_balancer *balancer,
+ request_rec *r,
+ proxy_server_conf *conf),(worker,
+ balancer,r,conf),DECLINED)
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups,
- (request_rec *r), (r),
- OK, DECLINED)
+ (request_rec *r), (r),
+ OK, DECLINED)