summaryrefslogtreecommitdiff
path: root/modules/proxy/proxy_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/proxy/proxy_util.c')
-rw-r--r--modules/proxy/proxy_util.c430
1 files changed, 323 insertions, 107 deletions
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index d3dd0686..d05f0cdc 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -21,6 +21,7 @@
#include "apr_version.h"
#include "apr_hash.h"
#include "proxy_util.h"
+#include "ajp.h"
#if APR_HAVE_UNISTD_H
#include <unistd.h> /* for getpid() */
@@ -31,6 +32,13 @@
#define apr_socket_create apr_socket_create_ex
#endif
+#if APR_HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#if (APR_MAJOR_VERSION < 2)
+#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */
+#endif
+
APLOG_USE_MODULE(proxy);
/*
@@ -86,14 +94,20 @@ PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src,
char *thenil;
apr_size_t thelen;
+ /* special case handling */
+ if (!dlen) {
+ /* XXX: APR_ENOSPACE would be better */
+ return APR_EGENERAL;
+ }
+ if (!src) {
+ *dst = '\0';
+ return APR_SUCCESS;
+ }
thenil = apr_cpystrn(dst, src, dlen);
thelen = thenil - dst;
- /* Assume the typical case is smaller copying into bigger
- so we have a fast return */
- if ((thelen < dlen-1) || ((strlen(src)) == thelen)) {
+ if (src[thelen] == '\0') {
return APR_SUCCESS;
}
- /* XXX: APR_ENOSPACE would be better */
return APR_EGENERAL;
}
@@ -1218,11 +1232,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer,
} else {
action = "re-using";
}
+ balancer->s = shm;
+ balancer->s->index = i;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02337)
"%s shm[%d] (0x%pp) for %s", action, i, (void *)shm,
balancer->s->name);
- balancer->s = shm;
- balancer->s->index = i;
/* the below should always succeed */
lbmethod = ap_lookup_provider(PROXY_LBMETHOD, balancer->s->lbpname, "0");
if (lbmethod) {
@@ -1356,7 +1370,7 @@ static apr_status_t connection_cleanup(void *theconn)
ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923)
"Pooled connection 0x%pp for worker %s has been"
" already returned to the connection pool.", conn,
- worker->s->name);
+ ap_proxy_worker_name(conn->pool, worker));
return APR_SUCCESS;
}
@@ -1480,6 +1494,16 @@ static apr_status_t connection_destructor(void *resource, void *params,
* WORKER related...
*/
+PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
+ proxy_worker *worker)
+{
+ if (!(*worker->s->uds_path) || !p) {
+ /* just in case */
+ return worker->s->name;
+ }
+ return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL);
+}
+
PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
proxy_balancer *balancer,
proxy_server_conf *conf,
@@ -1495,6 +1519,10 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
char *url_copy;
int i;
+ if (!url) {
+ return NULL;
+ }
+
c = ap_strchr_c(url, ':');
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
return NULL;
@@ -1573,20 +1601,47 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
int do_malloc)
{
int rv;
- apr_uri_t uri;
+ apr_uri_t uri, urisock;
proxy_worker_shared *wshared;
- char *ptr;
+ char *ptr, *sockpath = NULL;
+ /*
+ * Look to see if we are using UDS:
+ * require format: unix:/path/foo/bar.sock|http://ignored/path2/
+ * This results in talking http to the socket at /path/foo/bar.sock
+ */
+ ptr = ap_strchr((char *)url, '|');
+ if (ptr) {
+ *ptr = '\0';
+ rv = apr_uri_parse(p, url, &urisock);
+ if (rv == APR_SUCCESS && !strcasecmp(urisock.scheme, "unix")) {
+ sockpath = ap_runtime_dir_relative(p, urisock.path);;
+ url = ptr+1; /* so we get the scheme for the uds */
+ }
+ else {
+ *ptr = '|';
+ }
+ }
rv = apr_uri_parse(p, url, &uri);
if (rv != APR_SUCCESS) {
- return "Unable to parse URL";
+ return apr_pstrcat(p, "Unable to parse URL: ", url, NULL);
}
- if (!uri.hostname || !uri.scheme) {
- return "URL must be absolute!";
+ if (!uri.scheme) {
+ return apr_pstrcat(p, "URL must be absolute!: ", url, NULL);
+ }
+ /* allow for unix:/path|http: */
+ if (!uri.hostname) {
+ if (sockpath) {
+ uri.hostname = "localhost";
+ }
+ else {
+ return apr_pstrcat(p, "URL must be absolute!: ", url, NULL);
+ }
+ }
+ else {
+ ap_str_tolower(uri.hostname);
}
-
- ap_str_tolower(uri.hostname);
ap_str_tolower(uri.scheme);
/*
* Workers can be associated w/ balancers or on their
@@ -1642,6 +1697,15 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT);
wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV);
wshared->was_malloced = (do_malloc != 0);
+ if (sockpath) {
+ if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) {
+ return apr_psprintf(p, "worker uds path (%s) too long", sockpath);
+ }
+
+ }
+ else {
+ *wshared->uds_path = '\0';
+ }
(*worker)->hash = wshared->hash;
(*worker)->context = NULL;
@@ -1670,12 +1734,18 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_worker(proxy_worker *worker, proxy_wo
} else {
action = "re-using";
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338)
- "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm,
- worker->s->name);
-
worker->s = shm;
worker->s->index = i;
+ {
+ apr_pool_t *pool;
+ apr_pool_create(&pool, ap_server_conf->process->pool);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338)
+ "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm,
+ ap_proxy_worker_name(pool, worker));
+ if (pool) {
+ apr_pool_destroy(pool);
+ }
+ }
return APR_SUCCESS;
}
@@ -1687,11 +1757,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser
if (worker->s->status & PROXY_WORKER_INITIALIZED) {
/* The worker is already initialized */
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00924)
- "worker %s shared already initialized", worker->s->name);
+ "worker %s shared already initialized",
+ ap_proxy_worker_name(p, worker));
}
else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00925)
- "initializing worker %s shared", worker->s->name);
+ "initializing worker %s shared",
+ ap_proxy_worker_name(p, worker));
/* Set default parameters */
if (!worker->s->retry_set) {
worker->s->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
@@ -1727,11 +1799,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser
/* What if local is init'ed and shm isn't?? Even possible? */
if (worker->local_status & PROXY_WORKER_INITIALIZED) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00926)
- "worker %s local already initialized", worker->s->name);
+ "worker %s local already initialized",
+ ap_proxy_worker_name(p, worker));
}
else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927)
- "initializing worker %s local", worker->s->name);
+ "initializing worker %s local",
+ ap_proxy_worker_name(p, worker));
apr_global_mutex_lock(proxy_mutex);
/* Now init local worker data */
if (worker->tmutex == NULL) {
@@ -2023,6 +2097,29 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
(*conn)->close = 0;
(*conn)->inreslist = 0;
+ if (*worker->s->uds_path) {
+ if ((*conn)->uds_path == NULL) {
+ /* use (*conn)->pool instead of worker->cp->pool to match lifetime */
+ (*conn)->uds_path = apr_pstrdup((*conn)->pool, worker->s->uds_path);
+ }
+ if ((*conn)->uds_path) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02545)
+ "%s: has determined UDS as %s",
+ proxy_function, (*conn)->uds_path);
+ }
+ else {
+ /* should never happen */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02546)
+ "%s: cannot determine UDS (%s)",
+ proxy_function, worker->s->uds_path);
+
+ }
+ }
+ else {
+ (*conn)->uds_path = NULL;
+ }
+
+
return OK;
}
@@ -2065,7 +2162,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
NULL));
}
if (!uri->port) {
- uri->port = apr_uri_port_of_scheme(uri->scheme);
+ uri->port = ap_proxy_port_of_scheme(uri->scheme);
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00944)
@@ -2094,7 +2191,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
* spilling the cached addr from the worker.
*/
if (!conn->hostname || !worker->s->is_address_reusable ||
- worker->s->disablereuse) {
+ worker->s->disablereuse || *worker->s->uds_path) {
if (proxyname) {
conn->hostname = apr_pstrdup(conn->pool, proxyname);
conn->port = proxyport;
@@ -2132,7 +2229,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
conn->port = uri->port;
}
socket_cleanup(conn);
- if (!worker->s->is_address_reusable || worker->s->disablereuse) {
+ if (!(*worker->s->uds_path) &&
+ (!worker->s->is_address_reusable || worker->s->disablereuse)) {
/*
* Only do a lookup if we should not reuse the backend address.
* Otherwise we will look it up once for the worker.
@@ -2143,7 +2241,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
conn->pool);
}
}
- if (worker->s->is_address_reusable && !worker->s->disablereuse) {
+ if (!(*worker->s->uds_path) && worker->s->is_address_reusable && !worker->s->disablereuse) {
/*
* Looking up the backend address for the worker only makes sense if
* we can reuse the address.
@@ -2372,6 +2470,52 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
}
+#if APR_HAVE_SYS_UN_H
+/* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */
+static apr_status_t socket_connect_un(apr_socket_t *sock,
+ struct sockaddr_un *sa)
+{
+ apr_status_t rv;
+ apr_os_sock_t rawsock;
+ apr_interval_time_t t;
+
+ rv = apr_os_sock_get(&rawsock, sock);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_timeout_get(sock, &t);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ do {
+ const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path)
+ + strlen(sa->sun_path) + 1;
+ rv = connect(rawsock, (struct sockaddr*)sa, addrlen);
+ } while (rv == -1 && errno == EINTR);
+
+ if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY)
+ && (t > 0)) {
+#if APR_MAJOR_VERSION < 2
+ rv = apr_wait_for_io_or_timeout(NULL, sock, 0);
+#else
+ rv = apr_socket_wait(sock, APR_WAIT_WRITE);
+#endif
+
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+ }
+
+ if (rv == -1 && errno != EISCONN) {
+ return errno;
+ }
+
+ return APR_SUCCESS;
+}
+#endif
+
PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_conn_rec *conn,
proxy_worker *worker,
@@ -2396,93 +2540,131 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
proxy_function);
}
}
- while (backend_addr && !connected) {
- if ((rv = apr_socket_create(&newsock, backend_addr->family,
- SOCK_STREAM, APR_PROTO_TCP,
- conn->scpool)) != APR_SUCCESS) {
- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952)
- "%s: error creating fam %d socket for target %s",
- proxy_function,
- backend_addr->family,
- worker->s->hostname);
- /*
- * this could be an IPv6 address from the DNS but the
- * local machine won't give us an IPv6 socket; hopefully the
- * DNS returned an additional address to try
- */
- backend_addr = backend_addr->next;
- continue;
- }
- conn->connection = NULL;
+ while ((backend_addr || conn->uds_path) && !connected) {
+#if APR_HAVE_SYS_UN_H
+ if (conn->uds_path)
+ {
+ struct sockaddr_un sa;
- if (worker->s->recv_buffer_size > 0 &&
- (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
- worker->s->recv_buffer_size))) {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953)
- "apr_socket_opt_set(SO_RCVBUF): Failed to set "
- "ProxyReceiveBufferSize, using default");
- }
+ rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0,
+ conn->scpool);
+ if (rv != APR_SUCCESS) {
+ loglevel = APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(02453)
+ "%s: error creating Unix domain socket for "
+ "target %s",
+ proxy_function,
+ worker->s->hostname);
+ break;
+ }
+ conn->connection = NULL;
- rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1);
- if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954)
- "apr_socket_opt_set(APR_TCP_NODELAY): "
- "Failed to set");
- }
+ sa.sun_family = AF_UNIX;
+ apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path));
- /* Set a timeout for connecting to the backend on the socket */
- if (worker->s->conn_timeout_set) {
- apr_socket_timeout_set(newsock, worker->s->conn_timeout);
- }
- else if (worker->s->timeout_set) {
- apr_socket_timeout_set(newsock, worker->s->timeout);
- }
- else if (conf->timeout_set) {
- apr_socket_timeout_set(newsock, conf->timeout);
- }
- else {
- apr_socket_timeout_set(newsock, s->timeout);
- }
- /* Set a keepalive option */
- if (worker->s->keepalive) {
- if ((rv = apr_socket_opt_set(newsock,
- APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955)
- "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
- " Keepalive");
+ rv = socket_connect_un(newsock, &sa);
+ if (rv != APR_SUCCESS) {
+ apr_socket_close(newsock);
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454)
+ "%s: attempt to connect to Unix domain socket "
+ "%s (%s) failed",
+ proxy_function,
+ conn->uds_path,
+ worker->s->hostname);
+ break;
}
}
- ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s,
- "%s: fam %d socket created to connect to %s",
- proxy_function, backend_addr->family, worker->s->hostname);
+ else
+#endif
+ {
+ if ((rv = apr_socket_create(&newsock, backend_addr->family,
+ SOCK_STREAM, APR_PROTO_TCP,
+ conn->scpool)) != APR_SUCCESS) {
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952)
+ "%s: error creating fam %d socket for "
+ "target %s",
+ proxy_function,
+ backend_addr->family,
+ worker->s->hostname);
+ /*
+ * this could be an IPv6 address from the DNS but the
+ * local machine won't give us an IPv6 socket; hopefully the
+ * DNS returned an additional address to try
+ */
+ backend_addr = backend_addr->next;
+ continue;
+ }
+ conn->connection = NULL;
+
+ if (worker->s->recv_buffer_size > 0 &&
+ (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
+ worker->s->recv_buffer_size))) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953)
+ "apr_socket_opt_set(SO_RCVBUF): Failed to set "
+ "ProxyReceiveBufferSize, using default");
+ }
- if (conf->source_address_set) {
- local_addr = apr_pmemdup(conn->pool, conf->source_address,
- sizeof(apr_sockaddr_t));
- local_addr->pool = conn->pool;
- rv = apr_socket_bind(newsock, local_addr);
- if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956)
- "%s: failed to bind socket to local address",
- proxy_function);
+ rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1);
+ if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954)
+ "apr_socket_opt_set(APR_TCP_NODELAY): "
+ "Failed to set");
}
- }
- /* make the connection out of the socket */
- rv = apr_socket_connect(newsock, backend_addr);
+ /* Set a timeout for connecting to the backend on the socket */
+ if (worker->s->conn_timeout_set) {
+ apr_socket_timeout_set(newsock, worker->s->conn_timeout);
+ }
+ else if (worker->s->timeout_set) {
+ apr_socket_timeout_set(newsock, worker->s->timeout);
+ }
+ else if (conf->timeout_set) {
+ apr_socket_timeout_set(newsock, conf->timeout);
+ }
+ else {
+ apr_socket_timeout_set(newsock, s->timeout);
+ }
+ /* Set a keepalive option */
+ if (worker->s->keepalive) {
+ if ((rv = apr_socket_opt_set(newsock,
+ APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955)
+ "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
+ " Keepalive");
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s,
+ "%s: fam %d socket created to connect to %s",
+ proxy_function, backend_addr->family, worker->s->hostname);
+
+ if (conf->source_address_set) {
+ local_addr = apr_pmemdup(conn->pool, conf->source_address,
+ sizeof(apr_sockaddr_t));
+ local_addr->pool = conn->pool;
+ rv = apr_socket_bind(newsock, local_addr);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956)
+ "%s: failed to bind socket to local address",
+ proxy_function);
+ }
+ }
- /* if an error occurred, loop round and try again */
- if (rv != APR_SUCCESS) {
- apr_socket_close(newsock);
- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957)
- "%s: attempt to connect to %pI (%s) failed",
- proxy_function,
- backend_addr,
- worker->s->hostname);
- backend_addr = backend_addr->next;
- continue;
+ /* make the connection out of the socket */
+ rv = apr_socket_connect(newsock, backend_addr);
+
+ /* if an error occurred, loop round and try again */
+ if (rv != APR_SUCCESS) {
+ apr_socket_close(newsock);
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957)
+ "%s: attempt to connect to %pI (%s) failed",
+ proxy_function,
+ backend_addr,
+ worker->s->hostname);
+ backend_addr = backend_addr->next;
+ continue;
+ }
}
/* Set a timeout on the socket */
@@ -2498,7 +2680,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
conn->sock = newsock;
- if (conn->forward) {
+ if (!conn->uds_path && conn->forward) {
forward_info *forward = (forward_info *)conn->forward;
/*
* For HTTP CONNECT we need to prepend CONNECT request before
@@ -2779,7 +2961,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec
found = 1;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02402)
"re-grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm,
- worker->s->name);
+ ap_proxy_worker_name(conf->pool, worker));
break;
}
}
@@ -3190,6 +3372,9 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
if (transferred != -1)
p_conn->worker->s->transferred += transferred;
status = ap_pass_brigade(origin->output_filters, bb);
+ /* Cleanup the brigade now to avoid buckets lifetime
+ * issues in case of error returned below. */
+ apr_brigade_cleanup(bb);
if (status != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01084)
"pass request body failed to %pI (%s)",
@@ -3209,10 +3394,41 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
return HTTP_BAD_REQUEST;
}
}
- apr_brigade_cleanup(bb);
return OK;
}
+/* Fill in unknown schemes from apr_uri_port_of_scheme() */
+
+typedef struct proxy_schemes_t {
+ const char *name;
+ apr_port_t default_port;
+} proxy_schemes_t ;
+
+static proxy_schemes_t pschemes[] =
+{
+ {"fcgi", 8000},
+ {"ajp", AJP13_DEF_PORT},
+ { NULL, 0xFFFF } /* unknown port */
+};
+
+PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme)
+{
+ if (scheme) {
+ apr_port_t port;
+ if ((port = apr_uri_port_of_scheme(scheme)) != 0) {
+ return port;
+ } else {
+ proxy_schemes_t *pscheme;
+ for (pscheme = pschemes; pscheme->name != NULL; ++pscheme) {
+ if (strcasecmp(scheme, pscheme->name) == 0) {
+ return pscheme->default_port;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
void proxy_util_register_hooks(apr_pool_t *p)
{
APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);