]> granicus.if.org Git - apache/commitdiff
Merge r1451633, r1451905, r1451921, r1452259, r1453981, r1501913, r1513508, r1531340...
authorJim Jagielski <jim@apache.org>
Tue, 21 Jan 2014 16:44:04 +0000 (16:44 +0000)
committerJim Jagielski <jim@apache.org>
Tue, 21 Jan 2014 16:44:04 +0000 (16:44 +0000)
Add in rough uds support (Bugx 54101) from Blaise Tarr <blaise.tarr@gmail.com>

Make AF_UNIX aware... fix Windows/Netware??

Follow-up to r1451905 to fix NetWare/Windows compilation.

apr trunk-able

message tag for dom sock

Note about new UDS support

UDS subsequent request on a connection fix

Reformat the UDS support inline with a new naming structure.
Use a flag for speed for testing.

syntax sugar... if the worker is associated w/ a UDS,
then make sure the log reporting has a visual clue.

Ensure that userland format of UDS is the same as how it is
configured, no matter how we store and use it internally.

Eclipse code analysis warning

UDS urls need to be desockified when configuring...
Submitted by: jim, fuankg, jim, jim, druggeri, druggeri, jim, jim, jim, jim, jim
Reviewed/backported by: jim

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1560081 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
docs/manual/mod/mod_proxy.xml
include/ap_mmn.h
modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/mod_proxy_balancer.c
modules/proxy/proxy_util.c

diff --git a/CHANGES b/CHANGES
index aa745101e0530bec1605fdea299bf6c487eb796d..c04f48f1d71de900d1b078f469b967d111fcb0d9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -66,6 +66,10 @@ Changes with Apache 2.4.7
      keys, and unconditionally disable aNULL, eNULL and EXP ciphers
      (not overridable via SSLCipherSuite). [Kaspar Brand]
 
+  *) mod_proxy: Added support for unix domain sockets as the
+     backend server endpoint [Jim Jagielski, Blaise Tarr
+     <blaise tarr gmail com>]
+
   *) Add experimental cmake-based build system for Windows.  [Jeff Trawick,
      Tom Donovan]
 
diff --git a/STATUS b/STATUS
index 8ef3033c04300373c5089ade2744dab9504958b4..440cefe624eaf7c6bd149fcfbca13e21793d8b73 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -98,22 +98,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  * mod_proxy: support Unix domain sockets
-    trunk patch: https://svn.apache.org/viewvc?view=revision&revision=1451633
-                 https://svn.apache.org/viewvc?view=revision&revision=1451905
-                 https://svn.apache.org/viewvc?view=revision&revision=1451921
-                 https://svn.apache.org/viewvc?view=revision&revision=1452259
-                 https://svn.apache.org/viewvc?view=revision&revision=1453981
-                 https://svn.apache.org/viewvc?view=revision&revision=1501913
-                 https://svn.apache.org/viewvc?view=revision&revision=1513508
-                 https://svn.apache.org/viewvc?view=revision&revision=1531340
-                 https://svn.apache.org/viewvc?view=revision&revision=1531370
-                 https://svn.apache.org/viewvc?view=revision&revision=1531962
-                 https://svn.apache.org/viewvc?view=revision&revision=1533065
-                 https://svn.apache.org/viewvc?view=revision&revision=1540052
-    2.4.x patch: http://people.apache.org/~jim/patches/uds-2.4.patch
-    +1: jim, druggeri, humbedooh
-
   * mod_ssl: address the "init functions should return status code rather
     than ssl_die()" todo from 2002 (avoid orphan IPC objects after startup
     or reload failures, see also the "ssl_die() and pool cleanup" thread
index dd939941b9c05f77431c9bc7a68b19bd1ec9c161..987f46a60c9727c4ea27a12ef65d919141bea017 100644 (file)
@@ -837,6 +837,14 @@ expressions</description>
     usually be set <strong>off</strong> when using
     <directive>ProxyPass</directive>.</note>
 
+    <p>Support for using a Unix Domain Socket is available by using a target
+    which prepends <code>unix:/path/lis.sock|</code>. For example, to proxy
+    HTTP and target the UDS at /home/www/socket you would use
+    <code>unix:/home/www.socket|http://localhost/whatever/</code>.</p>
+
+    <note><strong>Note:</strong> The path associated with the <code>unix:</code>
+    URL is <directive>DefaultRuntimeDir</directive> aware.</note>
+
     <p>Suppose the local server has address <code>http://example.com/</code>;
     then</p>
 
index 115e769fd7ca48cb11887aa84a147f1589cc6f46..c95274246e06c70fb19b0fdf170fd199bedb8e26 100644 (file)
  * 20120211.26 (2.4.7-dev) Add util_fcgi.h, FastCGI protocol support
  * 20120211.27 (2.4.7-dev) Add ap_podx_restart_t and ap_mpm_podx_*
  * 20120211.28 (2.4.7-dev) Add ap_regname
+ * 20120211.29 (2.4.7-dev) Add uds_path to proxy_conn_rec
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20120211
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 28                   /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 29                   /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 15ba32a379e730ca941d4893519acd0f55ac8ade..60e3e28f7a3be8225d30f6e0ed6989fff86ea50c 100644 (file)
@@ -1370,7 +1370,6 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
     return new;
 }
 
-
 static const char *
     add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
 {
@@ -1445,6 +1444,36 @@ static const char *
     return add_proxy(cmd, dummy, f1, r1, 1);
 }
 
+static char *de_socketfy(apr_pool_t *p, char *url)
+{
+    char *ptr;
+    /*
+     * We could be passed a URL during the config stage that contains
+     * the UDS path... ignore it
+     */
+    if (!strncasecmp(url, "unix:", 5) &&
+        ((ptr = ap_strchr(url, '|')) != NULL)) {
+        /* move past the 'unix:...|' UDS path info */
+        char *ret, *c;
+
+        ret = ptr + 1;
+        /* special case: "unix:....|scheme:" is OK, expand
+         * to "unix:....|scheme://localhost"
+         * */
+        c = ap_strchr(ret, ':');
+        if (c == NULL) {
+            return NULL;
+        }
+        if (c[1] == '\0') {
+            return apr_pstrcat(p, ret, "//localhost", NULL);
+        }
+        else {
+            return ret;
+        }
+    }
+    return url;
+}
+
 static const char *
     add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex)
 {
@@ -1536,7 +1565,7 @@ static const char *
     }
 
     new->fake = apr_pstrdup(cmd->pool, f);
-    new->real = apr_pstrdup(cmd->pool, r);
+    new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r));
     new->flags = flags;
     if (use_regex) {
         new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
@@ -1572,7 +1601,7 @@ static const char *
         new->balancer = balancer;
     }
     else {
-        proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, r);
+        proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r));
         int reuse = 0;
         if (!worker) {
             const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0);
@@ -1584,14 +1613,14 @@ static const char *
             reuse = 1;
             ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145)
                          "Sharing worker '%s' instead of creating new worker '%s'",
-                         worker->s->name, new->real);
+                         ap_proxy_worker_name(cmd->pool, worker), new->real);
         }
 
         for (i = 0; i < arr->nelts; i++) {
             if (reuse) {
                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01146)
                              "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing",
-                             elts[i].key, elts[i].val, worker->s->name);
+                             elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker));
             } else {
                 const char *err = set_worker_param(cmd->pool, worker, elts[i].key,
                                                    elts[i].val);
@@ -2048,7 +2077,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
     }
 
     /* Try to find existing worker */
-    worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, name);
+    worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name));
     if (!worker) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147)
                      "Defining worker '%s' for balancer '%s'",
@@ -2057,13 +2086,13 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
             return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01148)
                      "Defined worker '%s' for balancer '%s'",
-                     worker->s->name, balancer->s->name);
+                     ap_proxy_worker_name(cmd->pool, worker), balancer->s->name);
         PROXY_COPY_CONF_PARAMS(worker, conf);
     } else {
         reuse = 1;
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01149)
                      "Sharing worker '%s' instead of creating new worker '%s'",
-                     worker->s->name, name);
+                     ap_proxy_worker_name(cmd->pool, worker), name);
     }
 
     arr = apr_table_elts(params);
@@ -2072,7 +2101,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
         if (reuse) {
             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01150)
                          "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing",
-                         elts[i].key, elts[i].val, worker->s->name);
+                         elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker));
         } else {
             err = set_worker_param(cmd->pool, worker, elts[i].key,
                                                elts[i].val);
@@ -2134,7 +2163,7 @@ static const char *
         }
     }
     else {
-        worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, name);
+        worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name));
         if (!worker) {
             if (in_proxy_section) {
                 err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
@@ -2274,7 +2303,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
         }
         else {
             worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf,
-                                         conf->p);
+                                         de_socketfy(cmd->temp_pool, (char*)conf->p));
             if (!worker) {
                 err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
                                           sconf, conf->p, 0);
index 0afa8543f516e0336a5b94eed5c87e1a20dfbd4a..9d27ae01e96943ac3c6732b87f19c8ecc8fa7f33 100644 (file)
@@ -253,6 +253,7 @@ typedef struct {
     unsigned int need_flush:1; /* Flag to decide whether we need to flush the
                                 * filter chain or not */
     unsigned int inreslist:1;  /* connection in apr_reslist? */
+    const char   *uds_path;    /* Unix domain socket path */
 } proxy_conn_rec;
 
 typedef struct {
@@ -345,6 +346,7 @@ typedef struct {
     char      route[PROXY_WORKER_MAX_ROUTE_SIZE];     /* balancing route */
     char      redirect[PROXY_WORKER_MAX_ROUTE_SIZE];  /* temporary balancing redirection route */
     char      flusher[PROXY_WORKER_MAX_SCHEME_SIZE];  /* flush provider used by mod_proxy_fdpass */
+    char      uds_path[PROXY_WORKER_MAX_NAME_SIZE];   /* path to worker's unix domain socket if applicable */
     int             lbset;      /* load balancer cluster set */
     int             retries;    /* number of retries on this worker */
     int             lbstatus;   /* Current lbstatus */
@@ -589,6 +591,16 @@ typedef __declspec(dllimport) const char *
 
 
 /* Connection pool API */
+/**
+ * Return the user-land, UDS aware worker name
+ * @param p        memory pool used for displaying worker name
+ * @param worker   the worker
+ * @return         name
+ */
+
+PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p,
+                                           proxy_worker *worker);
+
 /**
  * Get the worker from proxy configuration
  * @param p        memory pool used for finding worker
index 5fd9e1513c29845243228d626162ebf2561d6962..c927d3bf6e5f0529212ea6fa6c5d8b867e2a02b2 100644 (file)
@@ -118,7 +118,8 @@ static void init_balancer_members(apr_pool_t *p, server_rec *s,
         int worker_is_initialized;
         proxy_worker *worker = *workers;
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01158)
-                     "Looking at %s -> %s initialized?", balancer->s->name, worker->s->name);
+                     "Looking at %s -> %s initialized?", balancer->s->name,
+                     ap_proxy_worker_name(p, worker));
         worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(worker);
         if (!worker_is_initialized) {
             ap_proxy_initialize_worker(worker, s, p);
@@ -638,10 +639,11 @@ static int proxy_balancer_post_request(proxy_worker *worker,
             int val = ((int *)balancer->errstatuses->elts)[i];
             if (r->status == val) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01174)
-                              "%s: Forcing worker (%s) into error state " 
+                              "%s: Forcing worker (%s) into error state "
                               "due to status code %d matching 'failonstatus' "
                               "balancer parameter",
-                              balancer->s->name, worker->s->name, val);
+                              balancer->s->name, ap_proxy_worker_name(r->pool, worker),
+                              val);
                 worker->s->status |= PROXY_WORKER_IN_ERROR;
                 worker->s->error_time = apr_time_now();
                 break;
@@ -654,7 +656,7 @@ static int proxy_balancer_post_request(proxy_worker *worker,
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02460)
                       "%s: Forcing worker (%s) into error state "
                       "due to timeout and 'failonstatus' parameter being set",
-                       balancer->s->name, worker->s->name);
+                       balancer->s->name, ap_proxy_worker_name(r->pool, worker));
         worker->s->status |= PROXY_WORKER_IN_ERROR;
         worker->s->error_time = apr_time_now();
 
@@ -1282,7 +1284,7 @@ static int balancer_handler(request_rec *r)
                 worker = *workers;
                 /* Start proxy_worker */
                 ap_rputs("        <httpd:worker>\n", r);
-                ap_rvputs(r, "          <httpd:name>", worker->s->name,
+                ap_rvputs(r, "          <httpd:name>", ap_proxy_worker_name(r->pool, worker),
                           "</httpd:name>\n", NULL);
                 ap_rvputs(r, "          <httpd:scheme>", worker->s->scheme,
                           "</httpd:scheme>\n", NULL);
@@ -1531,7 +1533,8 @@ static int balancer_handler(request_rec *r)
                           ap_escape_uri(r->pool, worker->s->name),
                           "&nonce=", balancer->s->nonce,
                           "\">", NULL);
-                ap_rvputs(r, worker->s->name, "</a></td>", NULL);
+                ap_rvputs(r, (*worker->s->uds_path ? "<i>" : ""), ap_proxy_worker_name(r->pool, worker),
+                          (*worker->s->uds_path ? "</i>" : ""), "</a></td>", NULL);
                 ap_rvputs(r, "<td>", ap_escape_html(r->pool, worker->s->route),
                           NULL);
                 ap_rvputs(r, "</td><td>",
@@ -1556,7 +1559,7 @@ static int balancer_handler(request_rec *r)
         ap_rputs("<hr />\n", r);
         if (wsel && bsel) {
             ap_rputs("<h3>Edit worker settings for ", r);
-            ap_rvputs(r, wsel->s->name, "</h3>\n", NULL);
+            ap_rvputs(r, (*wsel->s->uds_path?"<i>":""), ap_proxy_worker_name(r->pool, wsel), (*wsel->s->uds_path?"</i>":""), "</h3>\n", NULL);
             ap_rputs("<form method=\"POST\" enctype=\"application/x-www-form-urlencoded\" action=\"", r);
             ap_rvputs(r, ap_escape_uri(r->pool, action), "\">\n", NULL);
             ap_rputs("<dl>\n<table><tr><td>Load factor:</td><td><input name='w_lf' id='w_lf' type=text ", r);
index d3dd06868e91e4a25ae5d56a4eb0e7c2b35db910..347604f78e7d99258781cfd0d8ba2816ac2f6adf 100644 (file)
 #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 +93,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 +1231,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 +1369,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 +1493,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 +1518,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 +1600,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 +1696,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 +1733,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 +1756,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 +1798,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 +2096,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;
 }
 
@@ -2094,7 +2190,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 +2228,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 +2240,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 +2469,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 +2539,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 +2679,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 +2960,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;
             }
         }